Snap for 10447354 from d212ec450807f0029bb95cb37040f9126d751761 to mainline-cellbroadcast-release

Change-Id: I8f536eeca161808d7002d77ee05efc931dbaf609
diff --git a/Android.mk b/Android.mk
index 7f739fb..14b5358 100644
--- a/Android.mk
+++ b/Android.mk
@@ -72,7 +72,7 @@
 	# add in the local wts py files for use with the prebuilt
 	$(hide) zip -r $(WTS_ACTS_DISTRO_ARCHIVE) -j tools/test/connectivity/wts-acts/*.py
 	# create executable tool from the archive
-	$(hide) echo '#!/usr/bin/env python' | cat - $(WTS_ACTS_DISTRO_DIR)/wts-acts.zip > $(WTS_ACTS_DISTRO_DIR)/wts-acts
+	$(hide) echo '#!/usr/bin/env python3' | cat - $(WTS_ACTS_DISTRO_DIR)/wts-acts.zip > $(WTS_ACTS_DISTRO_DIR)/wts-acts
 	$(hide) chmod 755 $(WTS_ACTS_DISTRO)
 
 wts-acts: $(WTS_ACTS_DISTRO)
diff --git a/acts/framework/acts/base_test.py b/acts/framework/acts/base_test.py
index 6bf9424..a3b6546 100755
--- a/acts/framework/acts/base_test.py
+++ b/acts/framework/acts/base_test.py
@@ -101,9 +101,9 @@
     test_instance = event.test_class
     try:
         for fd in getattr(test_instance, 'fuchsia_devices', []):
-            if not fd.skip_sl4f:
-                fd.logging_lib.logI("%s BEGIN %s" %
-                                    (TEST_CASE_TOKEN, event.test_case_name))
+            if hasattr(fd, '_sl4f'):
+                fd.sl4f.logging_lib.logI(
+                    "%s BEGIN %s" % (TEST_CASE_TOKEN, event.test_case_name))
 
     except Exception as e:
         test_instance.log.warning(
@@ -118,9 +118,9 @@
     test_instance = event.test_class
     try:
         for fd in getattr(test_instance, 'fuchsia_devices', []):
-            if not fd.skip_sl4f:
-                fd.logging_lib.logI("%s END %s" %
-                                    (TEST_CASE_TOKEN, event.test_case_name))
+            if hasattr(fd, '_sl4f'):
+                fd.sl4f.logging_lib.logI(
+                    "%s END %s" % (TEST_CASE_TOKEN, event.test_case_name))
 
     except Exception as e:
         test_instance.log.warning(
@@ -405,6 +405,7 @@
             test_name: Name of the test that triggered this function.
             begin_time: Logline format timestamp taken when the test started.
         """
+
     def _on_pass(self, record):
         """Proxy function to guarantee the base implementation of on_pass is
         called.
@@ -429,6 +430,7 @@
             test_name: Name of the test that triggered this function.
             begin_time: Logline format timestamp taken when the test started.
         """
+
     def _on_skip(self, record):
         """Proxy function to guarantee the base implementation of on_skip is
         called.
@@ -450,6 +452,7 @@
             test_name: Name of the test that triggered this function.
             begin_time: Logline format timestamp taken when the test started.
         """
+
     def _on_exception(self, record):
         """Proxy function to guarantee the base implementation of on_exception
         is called.
@@ -471,6 +474,7 @@
             test_name: Name of the test that triggered this function.
             begin_time: Logline format timestamp taken when the test started.
         """
+
     def on_retry(self):
         """Function to run before retrying a test through get_func_with_retry.
 
@@ -478,6 +482,7 @@
         can be used to modify internal test parameters, for example, to retry
         a test with slightly different input variables.
         """
+
     def _exec_procedure_func(self, func, tr_record):
         """Executes a procedure function like on_pass, on_fail etc.
 
@@ -816,8 +821,10 @@
         # Run tests in order.
         test_case_iterations = self.user_params.get(
             keys.Config.key_test_case_iterations.value, 1)
-        if any([substr in self.__class__.__name__ for substr in
-                ['Preflight', 'Postflight']]):
+        if any([
+                substr in self.__class__.__name__
+                for substr in ['Preflight', 'Postflight']
+        ]):
             test_case_iterations = 1
         try:
             for test_name, test_func in tests:
diff --git a/acts/framework/acts/config_parser.py b/acts/framework/acts/config_parser.py
index a639c38..ed2aca5 100755
--- a/acts/framework/acts/config_parser.py
+++ b/acts/framework/acts/config_parser.py
@@ -13,7 +13,6 @@
 #   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 copy
 import itertools
 import os
 import sys
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index f45faf5..687ac94 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -18,6 +18,7 @@
 import ipaddress
 import os
 import time
+from typing import FrozenSet, Set
 
 from acts import logger
 from acts import utils
@@ -32,6 +33,10 @@
 from acts.controllers.ap_lib import hostapd_ap_preset
 from acts.controllers.ap_lib import hostapd_constants
 from acts.controllers.ap_lib import hostapd_config
+from acts.controllers.ap_lib import radvd
+from acts.controllers.ap_lib import radvd_config
+from acts.controllers.ap_lib.extended_capabilities import ExtendedCapabilities
+from acts.controllers.ap_lib.wireless_network_management import BssTransitionManagementRequest
 from acts.controllers.utils_lib.commands import ip
 from acts.controllers.utils_lib.commands import route
 from acts.controllers.utils_lib.commands import shell
@@ -88,26 +93,30 @@
     return [ap.ssh_settings.hostname for ap in aps]
 
 
-def setup_ap(access_point,
-             profile_name,
-             channel,
-             ssid,
-             mode=None,
-             preamble=None,
-             beacon_interval=None,
-             dtim_period=None,
-             frag_threshold=None,
-             rts_threshold=None,
-             force_wmm=None,
-             hidden=False,
-             security=None,
-             pmf_support=None,
-             additional_ap_parameters=None,
-             password=None,
-             n_capabilities=None,
-             ac_capabilities=None,
-             vht_bandwidth=None,
-             setup_bridge=False):
+def setup_ap(
+        access_point,
+        profile_name,
+        channel,
+        ssid,
+        mode=None,
+        preamble=None,
+        beacon_interval=None,
+        dtim_period=None,
+        frag_threshold=None,
+        rts_threshold=None,
+        force_wmm=None,
+        hidden=False,
+        security=None,
+        pmf_support=None,
+        additional_ap_parameters=None,
+        password=None,
+        n_capabilities=None,
+        ac_capabilities=None,
+        vht_bandwidth=None,
+        wnm_features: FrozenSet[hostapd_constants.WnmFeature] = frozenset(),
+        setup_bridge=False,
+        is_ipv6_enabled=False,
+        is_nat_enabled=True):
     """Creates a hostapd profile and runs it on an ap. This is a convenience
     function that allows us to start an ap with a single function, without first
     creating a hostapd config.
@@ -128,6 +137,13 @@
         additional_ap_parameters: Additional parameters to send the AP.
         password: Password to connect to WLAN if necessary.
         check_connectivity: Whether to check for internet connectivity.
+        wnm_features: WNM features to enable on the AP.
+        setup_bridge: Whether to bridge the LAN interface WLAN interface.
+            Only one WLAN interface can be bridged with the LAN interface
+            and none of the guest networks can be bridged.
+        is_ipv6_enabled: If True, start a IPv6 router advertisement daemon
+        is_nat_enabled: If True, start NAT on the AP to allow the DUT to be able
+            to access the internet if the WAN port is connected to the internet.
 
     Returns:
         An identifier for each ssid being started. These identifiers can be
@@ -154,10 +170,13 @@
                                             pmf_support=pmf_support,
                                             n_capabilities=n_capabilities,
                                             ac_capabilities=ac_capabilities,
-                                            vht_bandwidth=vht_bandwidth)
+                                            vht_bandwidth=vht_bandwidth,
+                                            wnm_features=wnm_features)
     return access_point.start_ap(
         hostapd_config=ap,
+        radvd_config=radvd_config.RadvdConfig() if is_ipv6_enabled else None,
         setup_bridge=setup_bridge,
+        is_nat_enabled=is_nat_enabled,
         additional_parameters=additional_ap_parameters)
 
 
@@ -192,8 +211,8 @@
             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: f'[Access Point|{self.ssh_settings.hostname}] {msg}')
         self.device_pdu_config = configs.get('PduDevice', None)
         self.identifier = self.ssh_settings.hostname
 
@@ -220,6 +239,7 @@
         self._aps = dict()
         self._dhcp = None
         self._dhcp_bss = dict()
+        self._radvd = None
         self.bridge = bridge_interface.BridgeInterface(self)
         self.iwconfig = ap_iwconfig.ApIwconfig(self)
 
@@ -258,20 +278,22 @@
             self.log.info('No hostapd running')
         # Bring down all wireless interfaces
         for iface in self.wlan:
-            WLAN_DOWN = 'ifconfig {} down'.format(iface)
+            WLAN_DOWN = f'ip link set {iface} down'
             self.ssh.run(WLAN_DOWN)
         # Bring down all bridge interfaces
         bridge_interfaces = self.interfaces.get_bridge_interface()
         if bridge_interfaces:
             for iface in bridge_interfaces:
-                BRIDGE_DOWN = 'ifconfig {} down'.format(iface)
-                BRIDGE_DEL = 'brctl delbr {}'.format(iface)
+                BRIDGE_DOWN = f'ip link set {iface} down'
+                BRIDGE_DEL = f'brctl delbr {iface}'
                 self.ssh.run(BRIDGE_DOWN)
                 self.ssh.run(BRIDGE_DEL)
 
     def start_ap(self,
                  hostapd_config,
+                 radvd_config=None,
                  setup_bridge=False,
+                 is_nat_enabled=True,
                  additional_parameters=None):
         """Starts as an ap using a set of configurations.
 
@@ -284,9 +306,14 @@
         Args:
             hostapd_config: hostapd_config.HostapdConfig, The configurations
                 to use when starting up the ap.
+            radvd_config: radvd_config.RadvdConfig, The IPv6 configuration
+                to use when starting up the ap.
             setup_bridge: Whether to bridge the LAN interface WLAN interface.
                 Only one WLAN interface can be bridged with the LAN interface
                 and none of the guest networks can be bridged.
+            is_nat_enabled: If True, start NAT on the AP to allow the DUT to be
+                able to access the internet if the WAN port is connected to the
+                internet.
             additional_parameters: A dictionary of parameters that can sent
                 directly into the hostapd config file.  This can be used for
                 debugging and or adding one off parameters into the config.
@@ -315,7 +342,7 @@
         # up to 8 different mac addresses. So in for one interface the range is
         # hex 0-7 and for the other the range is hex 8-f.
         interface_mac_orig = None
-        cmd = "ifconfig %s|grep ether|awk -F' ' '{print $2}'" % interface
+        cmd = f"ip link show {interface}|grep ether|awk -F' ' '{{print $2}}'"
         interface_mac_orig = self.ssh.run(cmd)
         if interface == self.wlan_5g:
             hostapd_config.bssid = interface_mac_orig.stdout[:-1] + '0'
@@ -325,7 +352,7 @@
             last_octet = 9
         if interface in self._aps:
             raise ValueError('No WiFi interface available for AP on '
-                             'channel %d' % hostapd_config.channel)
+                             f'channel {hostapd_config.channel}')
 
         apd = hostapd.Hostapd(self.ssh, interface)
         new_instance = _ApInstance(hostapd=apd, subnet=subnet)
@@ -358,8 +385,7 @@
                     starting_ip_range = self._AP_5G_SUBNET_STR
                 a, b, c, d = starting_ip_range.split('.')
                 self._dhcp_bss[bss] = dhcp_config.Subnet(
-                    ipaddress.ip_network('%s.%s.%s.%s' %
-                                         (a, b, str(int(c) + counter), d)))
+                    ipaddress.ip_network(f'{a}.{b}.{int(c) + counter}.{d}'))
                 counter = counter + 1
                 last_octet = last_octet + 1
 
@@ -368,7 +394,7 @@
         # The DHCP serer requires interfaces to have ips and routes before
         # the server will come up.
         interface_ip = ipaddress.ip_interface(
-            '%s/%s' % (subnet.router, subnet.network.netmask))
+            f'{subnet.router}/{subnet.network.netmask}')
         if setup_bridge is True:
             bridge_interface_name = 'eth_test'
             self.create_bridge(bridge_interface_name, [interface, self.lan])
@@ -382,15 +408,24 @@
             # variables represent the interface name, k, and dhcp info, v.
             for k, v in self._dhcp_bss.items():
                 bss_interface_ip = ipaddress.ip_interface(
-                    '%s/%s' % (self._dhcp_bss[k].router,
-                               self._dhcp_bss[k].network.netmask))
+                    f'{self._dhcp_bss[k].router}/{self._dhcp_bss[k].network.netmask}'
+                )
                 self._ip_cmd.set_ipv4_address(str(k), bss_interface_ip)
 
         # Restart the DHCP server with our updated list of subnets.
         configured_subnets = self.get_configured_subnets()
         dhcp_conf = dhcp_config.DhcpConfig(subnets=configured_subnets)
         self.start_dhcp(dhcp_conf=dhcp_conf)
-        self.start_nat()
+        if is_nat_enabled:
+            self.start_nat()
+            self.enable_forwarding()
+        else:
+            self.stop_nat()
+            self.enable_forwarding()
+        if radvd_config:
+            radvd_interface = bridge_interface_name if setup_bridge else interface
+            self._radvd = radvd.Radvd(self.ssh, radvd_interface)
+            self._radvd.start(radvd_config)
 
         bss_interfaces = [bss for bss in hostapd_config.bss_lookup]
         bss_interfaces.append(interface)
@@ -458,6 +493,15 @@
                 identifier).hostapd.pull_logs()
         return hostapd_logs
 
+    def enable_forwarding(self):
+        """Enable IPv4 and IPv6 forwarding on the AP.
+
+        When forwarding is enabled, the access point is able to route IP packets
+        between devices in the same subnet.
+        """
+        self.ssh.run('echo 1 > /proc/sys/net/ipv4/ip_forward')
+        self.ssh.run('echo 1 > /proc/sys/net/ipv6/conf/all/forwarding')
+
     def start_nat(self):
         """Start NAT on the AP.
 
@@ -472,10 +516,8 @@
         # WLAN/LAN ports will be able to access the internet if the WAN port
         # is connected to the internet.
         self.ssh.run('iptables -t nat -F')
-        self.ssh.run('iptables -t nat -A POSTROUTING -o %s -j MASQUERADE' %
-                     self.wan)
-        self.ssh.run('echo 1 > /proc/sys/net/ipv4/ip_forward')
-        self.ssh.run('echo 1 > /proc/sys/net/ipv6/conf/all/forwarding')
+        self.ssh.run(
+            f'iptables -t nat -A POSTROUTING -o {self.wan} -j MASQUERADE')
 
     def stop_nat(self):
         """Stop NAT on the AP.
@@ -487,8 +529,6 @@
         per-interface masquerade rules.
         """
         self.ssh.run('iptables -t nat -F')
-        self.ssh.run('echo 0 > /proc/sys/net/ipv4/ip_forward')
-        self.ssh.run('echo 0 > /proc/sys/net/ipv6/conf/all/forwarding')
 
     def create_bridge(self, bridge_name, interfaces):
         """Create the specified bridge and bridge the specified interfaces.
@@ -499,15 +539,12 @@
         """
 
         # Create the bridge interface
-        self.ssh.run(
-            'brctl addbr {bridge_name}'.format(bridge_name=bridge_name))
+        self.ssh.run(f'brctl addbr {bridge_name}')
 
         for interface in interfaces:
-            self.ssh.run('brctl addif {bridge_name} {interface}'.format(
-                bridge_name=bridge_name, interface=interface))
+            self.ssh.run(f'brctl addif {bridge_name} {interface}')
 
-        self.ssh.run(
-            'ip link set {bridge_name} up'.format(bridge_name=bridge_name))
+        self.ssh.run(f'ip link set {bridge_name} up')
 
     def remove_bridge(self, bridge_name):
         """Removes the specified bridge
@@ -521,17 +558,13 @@
         #
         # Or if we're doing 2.4Ghz and 5Ghz SSIDs and we've already torn
         # down the bridge once, but we got called for each band.
-        result = self.ssh.run(
-            'brctl show {bridge_name}'.format(bridge_name=bridge_name),
-            ignore_status=True)
+        result = self.ssh.run(f'brctl show {bridge_name}', ignore_status=True)
 
         # If the bridge exists, we'll get an exit_status of 0, indicating
         # success, so we can continue and remove the bridge.
         if result.exit_status == 0:
-            self.ssh.run('ip link set {bridge_name} down'.format(
-                bridge_name=bridge_name))
-            self.ssh.run(
-                'brctl delbr {bridge_name}'.format(bridge_name=bridge_name))
+            self.ssh.run(f'ip link set {bridge_name} down')
+            self.ssh.run(f'brctl delbr {bridge_name}')
 
     def get_bssid_from_ssid(self, ssid, band):
         """Gets the BSSID from a provided SSID
@@ -548,18 +581,17 @@
 
         # Get the interface name associated with the given ssid.
         for interface in interfaces:
-            cmd = "iw dev %s info|grep ssid|awk -F' ' '{print $2}'" % (
-                str(interface))
-            iw_output = self.ssh.run(cmd)
+            iw_output = self.ssh.run(
+                f"iw dev {interface} info|grep ssid|awk -F' ' '{{print $2}}'")
             if 'command failed: No such device' in iw_output.stderr:
                 continue
             else:
                 # If the configured ssid is equal to the given ssid, we found
                 # the right interface.
                 if iw_output.stdout == ssid:
-                    cmd = "iw dev %s info|grep addr|awk -F' ' '{print $2}'" % (
-                        str(interface))
-                    iw_output = self.ssh.run(cmd)
+                    iw_output = self.ssh.run(
+                        f"iw dev {interface} info|grep addr|awk -F' ' '{{print $2}}'"
+                    )
                     return iw_output.stdout
         return None
 
@@ -571,23 +603,26 @@
         """
 
         if identifier not in list(self._aps.keys()):
-            raise ValueError('Invalid identifier %s given' % identifier)
+            raise ValueError(f'Invalid identifier {identifier} given')
 
         instance = self._aps.get(identifier)
 
-        instance.hostapd.stop()
+        if self._radvd:
+            self._radvd.stop()
         try:
             self.stop_dhcp()
         except dhcp_server.NoInterfaceError:
             pass
+        self.stop_nat()
+        instance.hostapd.stop()
         self._ip_cmd.clear_ipv4_addresses(identifier)
 
         del self._aps[identifier]
         bridge_interfaces = self.interfaces.get_bridge_interface()
         if bridge_interfaces:
             for iface in bridge_interfaces:
-                BRIDGE_DOWN = 'ifconfig {} down'.format(iface)
-                BRIDGE_DEL = 'brctl delbr {}'.format(iface)
+                BRIDGE_DOWN = f'ip link set {iface} down'
+                BRIDGE_DEL = f'brctl delbr {iface}'
                 self.ssh.run(BRIDGE_DOWN)
                 self.ssh.run(BRIDGE_DEL)
 
@@ -628,7 +663,7 @@
         iface_lan = self.lan
 
         a, b, c, _ = subnet_str.strip('/24').split('.')
-        bridge_ip = "%s.%s.%s.%s" % (a, b, c, BRIDGE_IP_LAST)
+        bridge_ip = f'{a}.{b}.{c}.{BRIDGE_IP_LAST}'
 
         configs = (iface_wlan, iface_lan, bridge_ip)
 
@@ -642,24 +677,21 @@
             send_ra_path: path where sendra path is located on server
         """
         self.scapy_install_path = self.ssh.run('mktemp -d').stdout.rstrip()
-        self.log.info("Scapy install path: %s" % self.scapy_install_path)
+        self.log.info(f'Scapy install path: {self.scapy_install_path}')
         self.ssh.send_file(scapy_path, self.scapy_install_path)
         self.ssh.send_file(send_ra_path, self.scapy_install_path)
 
         scapy = os.path.join(self.scapy_install_path,
                              scapy_path.split('/')[-1])
 
-        untar_res = self.ssh.run('tar -xvf %s -C %s' %
-                                 (scapy, self.scapy_install_path))
-
-        instl_res = self.ssh.run(
-            'cd %s; %s' % (self.scapy_install_path, SCAPY_INSTALL_COMMAND))
+        self.ssh.run(f'tar -xvf {scapy} -C {self.scapy_install_path}')
+        self.ssh.run(f'cd {self.scapy_install_path}; {SCAPY_INSTALL_COMMAND}')
 
     def cleanup_scapy(self):
         """ Cleanup scapy """
         if self.scapy_install_path:
-            cmd = 'rm -rf %s' % self.scapy_install_path
-            self.log.info("Cleaning up scapy %s" % cmd)
+            cmd = f'rm -rf {self.scapy_install_path}'
+            self.log.info(f'Cleaning up scapy {cmd}')
             output = self.ssh.run(cmd)
             self.scapy_install_path = None
 
@@ -681,10 +713,10 @@
           rtt: retrans timer of the RA packet
         """
         scapy_command = os.path.join(self.scapy_install_path, RA_SCRIPT)
-        options = ' -m %s -i %d -c %d -l %d -in %s -rtt %s' % (
-            mac, interval, count, lifetime, iface, rtt)
-        self.log.info("Scapy cmd: %s" % scapy_command + options)
-        res = self.ssh.run(scapy_command + options)
+        options = f' -m {mac} -i {interval} -c {count} -l {lifetime} -in {iface} -rtt {rtt}'
+        cmd = scapy_command + options
+        self.log.info(f'Scapy cmd: {cmd}')
+        self.ssh.run(cmd)
 
     def get_icmp6intype134(self):
         """Read the value of Icmp6InType134 and return integer.
@@ -692,8 +724,8 @@
         Returns:
             Integer value >0 if grep is successful; 0 otherwise.
         """
-        ra_count_str = self.ssh.run('grep Icmp6InType134 %s || true' %
-                                    PROC_NET_SNMP6).stdout
+        ra_count_str = self.ssh.run(
+            f'grep Icmp6InType134 {PROC_NET_SNMP6} || true').stdout
         if ra_count_str:
             return int(ra_count_str.split()[1])
 
@@ -762,13 +794,11 @@
         if hostapd_configs is None:
             hostapd_configs = []
 
-        self.log.info('Power cycling AccessPoint (%s)' %
-                      self.ssh_settings.hostname)
+        self.log.info(f'Power cycling')
         ap_pdu, ap_pdu_port = pdu.get_pdu_port_for_device(
             self.device_pdu_config, pdus)
 
-        self.log.info('Killing power to AccessPoint (%s)' %
-                      self.ssh_settings.hostname)
+        self.log.info(f'Killing power')
         ap_pdu.off(str(ap_pdu_port))
 
         self.log.info('Verifying AccessPoint is unreachable.')
@@ -783,12 +813,12 @@
                     'second.')
                 time.sleep(1)
         else:
-            raise ConnectionError('Failed to bring down AccessPoint (%s)' %
-                                  self.ssh_settings.hostname)
+            raise ConnectionError(
+                f'Failed to bring down AccessPoint ({self.ssh_settings.hostname})'
+            )
         self._aps.clear()
 
-        self.log.info('Restoring power to AccessPoint (%s)' %
-                      self.ssh_settings.hostname)
+        self.log.info(f'Restoring power')
         ap_pdu.on(str(ap_pdu_port))
 
         self.log.info('Waiting for AccessPoint to respond to pings.')
@@ -802,9 +832,9 @@
                                'Retrying in 1 second.')
                 time.sleep(1)
         else:
-            raise ConnectionError('Timed out waiting for AccessPoint (%s) to '
-                                  'respond to pings.' %
-                                  self.ssh_settings.hostname)
+            raise ConnectionError(
+                f'Timed out waiting for AccessPoint ({self.ssh_settings.hostname}) '
+                'to respond to pings.')
 
         self.log.info('Waiting for AccessPoint to allow ssh connection.')
         timeout = time.time() + ssh_timeout
@@ -819,15 +849,14 @@
                 self.log.info('AccessPoint available via ssh.')
                 break
         else:
-            raise ConnectionError('Timed out waiting for AccessPoint (%s) to '
-                                  'allow ssh connection.' %
-                                  self.ssh_settings.hostname)
+            raise ConnectionError(
+                f'Timed out waiting for AccessPoint ({self.ssh_settings.hostname}) '
+                'to allow ssh connection.')
 
         # Allow 5 seconds for OS to finish getting set up
         time.sleep(5)
         self._initial_ap()
-        self.log.info('AccessPoint (%s) power cycled successfully.' %
-                      self.ssh_settings.hostname)
+        self.log.info('Power cycled successfully')
 
         for settings in hostapd_configs:
             if type(settings) == hostapd_config.HostapdConfig:
@@ -845,8 +874,7 @@
                     'Items in hostapd_configs list must either be '
                     'hostapd.HostapdConfig objects or dictionaries.')
 
-            self.log.info('Restarting network (%s) on AccessPoint.' %
-                          config.ssid)
+            self.log.info(f'Restarting network {config.ssid}')
             self.start_ap(config,
                           setup_bridge=setup_bridge,
                           additional_parameters=additional_parameters)
@@ -854,14 +882,39 @@
     def channel_switch(self, identifier, channel_num):
         """Switch to a different channel on the given AP."""
         if identifier not in list(self._aps.keys()):
-            raise ValueError('Invalid identifier %s given' % identifier)
+            raise ValueError(f'Invalid identifier {identifier} given')
         instance = self._aps.get(identifier)
-        self.log.info('channel switch to channel {}'.format(channel_num))
+        self.log.info(f'channel switch to channel {channel_num}')
         instance.hostapd.channel_switch(channel_num)
 
     def get_current_channel(self, identifier):
         """Find the current channel on the given AP."""
         if identifier not in list(self._aps.keys()):
-            raise ValueError('Invalid identifier %s given' % identifier)
+            raise ValueError(f'Invalid identifier {identifier} given')
         instance = self._aps.get(identifier)
         return instance.hostapd.get_current_channel()
+
+    def get_stas(self, identifier) -> Set[str]:
+        """Return MAC addresses of all associated STAs on the given AP."""
+        if identifier not in list(self._aps.keys()):
+            raise ValueError(f'Invalid identifier {identifier} given')
+        instance = self._aps.get(identifier)
+        return instance.hostapd.get_stas()
+
+    def get_sta_extended_capabilities(self, identifier,
+                                      sta_mac: str) -> ExtendedCapabilities:
+        """Get extended capabilities for the given STA, as seen by the AP."""
+        if identifier not in list(self._aps.keys()):
+            raise ValueError(f'Invalid identifier {identifier} given')
+        instance = self._aps.get(identifier)
+        return instance.hostapd.get_sta_extended_capabilities(sta_mac)
+
+    def send_bss_transition_management_req(
+            self, identifier, sta_mac: str,
+            request: BssTransitionManagementRequest):
+        """Send a BSS Transition Management request to an associated STA."""
+        if identifier not in list(self._aps.keys()):
+            raise ValueError('Invalid identifier {identifier} given')
+        instance = self._aps.get(identifier)
+        return instance.hostapd.send_bss_transition_management_req(
+            sta_mac, request)
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index ca334aa..4e66b42 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -559,6 +559,17 @@
         }
         return info
 
+    def add_device_info(self, name, info):
+        """Add custom device info to the user_added_info section.
+
+        Adding the same info name the second time will override existing info.
+
+        Args:
+          name: string, name of this info.
+          info: serializable, content of the info.
+        """
+        self._user_added_device_info.update({name: info})
+
     def sdk_api_level(self):
         if self._sdk_api_level is not None:
             return self._sdk_api_level
@@ -971,11 +982,11 @@
         Returns:
         Linux UID for the apk.
         """
-        output = self.adb.shell("dumpsys package %s | grep userId=" % apk_name,
+        output = self.adb.shell("dumpsys package %s | grep -e userId= -e appId=" % apk_name,
                                 ignore_status=True)
-        result = re.search(r"userId=(\d+)", output)
+        result = re.search(r"userId=(\d+)|appId=(\d+)", output)
         if result:
-            return result.group(1)
+            return result.group(1) if result.group(1) else result.group(2)
         else:
             None
 
@@ -1387,7 +1398,7 @@
             try:
                 completed = self.adb.getprop("sys.boot_completed")
                 if completed == '1':
-                    self.log.debug("devie has rebooted")
+                    self.log.debug("Device has rebooted")
                     return
             except AdbError:
                 # adb shell calls may fail during certain period of booting
diff --git a/acts/framework/acts/controllers/android_lib/android_api.py b/acts/framework/acts/controllers/android_lib/android_api.py
index 634e44b..b2b8abd 100644
--- a/acts/framework/acts/controllers/android_lib/android_api.py
+++ b/acts/framework/acts/controllers/android_lib/android_api.py
@@ -13,7 +13,6 @@
 #   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 enum
 import logging
 import sys
 
@@ -36,8 +35,7 @@
     MAX = sys.maxsize
 
 
-def android_api(min_api=AndroidApi.OLDEST,
-                max_api=AndroidApi.LATEST):
+def android_api(min_api=AndroidApi.OLDEST, max_api=AndroidApi.LATEST):
     """Decorates a function to only be called for the given API range.
 
     Only gets called if the AndroidDevice in the args is within the specified
@@ -55,12 +53,14 @@
          min_api: The minimum API level. Can be an int or an AndroidApi value.
          max_api: The maximum API level. Can be an int or an AndroidApi value.
     """
+
     def get_api_level(*args, **_):
         for arg in args:
             if isinstance(arg, AndroidDevice):
                 return arg.sdk_api_level()
-        logging.getLogger().error('An AndroidDevice was not found in the given '
-                                  'arguments.')
+        logging.getLogger().error(
+            'An AndroidDevice was not found in the given '
+            'arguments.')
         return None
 
     return version_selector.set_version(get_api_level, min_api, max_api)
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
index a1b15db..79b35a6 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
@@ -93,7 +93,7 @@
             self.anritsu.get_BTS(md8475a.BtsNumber.BTS2)
         ]
 
-    def set_band_combination(self, bands):
+    def set_band_combination(self, bands, mimo_modes):
         """ Prepares the test equipment for the indicated band combination.
 
         The reason why this is implemented in a separate method and not calling
@@ -104,6 +104,7 @@
 
         Args:
             bands: a list of bands represented as ints or strings
+            mimo_modes: a list of LteSimulation.MimoMode to use for each carrier
         """
         self.num_carriers = len(bands)
 
@@ -706,7 +707,7 @@
     LTE_MAX_CARRIERS = 4
 
     # The maximum power that the equipment is able to transmit
-    MAX_DL_POWER = -30
+    MAX_DL_POWER = -10
 
     # Simulation config files in the callbox computer.
     # These should be replaced in the future by setting up
diff --git a/acts/framework/acts/controllers/anritsu_lib/mg3710a.py b/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
index a9df65d..14b0d90 100644
--- a/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
+++ b/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
@@ -18,10 +18,7 @@
 """
 
 import logging
-import time
 import socket
-from enum import Enum
-from enum import IntEnum
 
 from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
 from acts.controllers.anritsu_lib._anritsu_utils import NO_ERROR
@@ -56,8 +53,8 @@
         self.log.info("Opening Socket Connection with "
                       "Signal Generator MG3710A ({}) ".format(self._ipaddr))
         try:
-            self._sock = socket.create_connection(
-                (self._ipaddr, 49158), timeout=30)
+            self._sock = socket.create_connection((self._ipaddr, 49158),
+                                                  timeout=30)
             self.send_query("*IDN?", 60)
             self.log.info("Communication Signal Generator MG3710A OK.")
             self.log.info("Opened Socket connection to ({})"
@@ -698,8 +695,8 @@
         Returns:
             frequency offset
         """
-        return self.send_query(
-            "SOUR{}:RAD:ARB:WM{}:FREQ:OFFS?".format(sg, a_or_b))
+        return self.send_query("SOUR{}:RAD:ARB:WM{}:FREQ:OFFS?".format(
+            sg, a_or_b))
 
     def set_arb_freq_offset_aorb(self, a_or_b, offset, sg=1):
         """ Sets the frequency offset of Pattern A/Pattern B based on Baseband
diff --git a/acts/framework/acts/controllers/ap_lib/ap_iwconfig.py b/acts/framework/acts/controllers/ap_lib/ap_iwconfig.py
index 77b9263..16397e2 100644
--- a/acts/framework/acts/controllers/ap_lib/ap_iwconfig.py
+++ b/acts/framework/acts/controllers/ap_lib/ap_iwconfig.py
@@ -14,7 +14,6 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import logging
 from acts.libs.proc import job
 
 
diff --git a/acts/framework/acts/controllers/ap_lib/dhcp_config.py b/acts/framework/acts/controllers/ap_lib/dhcp_config.py
index ffc9db1..d7b3d02 100644
--- a/acts/framework/acts/controllers/ap_lib/dhcp_config.py
+++ b/acts/framework/acts/controllers/ap_lib/dhcp_config.py
@@ -12,9 +12,7 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import collections
 import copy
-import ipaddress
 
 _ROUTER_DNS = '8.8.8.8, 4.4.4.4'
 
diff --git a/acts/framework/acts/controllers/ap_lib/extended_capabilities.py b/acts/framework/acts/controllers/ap_lib/extended_capabilities.py
new file mode 100644
index 0000000..39d2f36
--- /dev/null
+++ b/acts/framework/acts/controllers/ap_lib/extended_capabilities.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+#
+#   Copyright 2021 - 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.
+#   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.
+
+from enum import IntEnum, unique
+from typing import Tuple
+
+
+@unique
+class ExtendedCapability(IntEnum):
+    """All extended capabilities present in IEEE 802.11-2020 Table 9-153.
+
+    Each name has a value corresponding to that extended capability's bit offset
+    in the specification's extended capabilities field.
+
+    Note that most extended capabilities are represented by a single bit, which
+    indicates whether the extended capability is advertised by the STA; but
+    some are represented by multiple bits. In the enum, each extended capability
+    has the value of its offset; comments indicate capabilities that use
+    multiple bits.
+    """
+    TWENTY_FORTY_BSS_COEXISTENCE_MANAGEMENT_SUPPORT = 0
+    GLK = 1
+    EXTENDED_CHANNEL_SWITCHING = 2
+    GLK_GCR = 3
+    PSMP_CAPABILITY = 4
+    # 5 reserved
+    S_PSMP_SUPPORT = 6
+    EVENT = 7
+    DIAGNOSTICS = 8
+    MULTICAST_DIAGNOSTICS = 9
+    LOCATION_TRACKING = 10
+    FMS = 11
+    PROXY_ARP_SERVICE = 12
+    COLLOCATED_INTERFERENCE_REPORTING = 13
+    CIVIC_LOCATION = 14
+    GEOSPATIAL_LOCATION = 15
+    TFS = 16
+    WNM_SLEEP_MODE = 17
+    TIM_BROADCAST = 18
+    BSS_TRANSITION = 19
+    QOS_TRAFFIC_CAPABILITY = 20
+    AC_STATION_COUNT = 21
+    MULTIPLE_BSSID = 22
+    TIMING_MEASUREMENT = 23
+    CHANNEL_USAGE = 24
+    SSID_LIST = 25
+    DMS = 26
+    UTC_TSF_OFFSET = 27
+    TPU_BUFFER_STA_SUPPORT = 28
+    TDLS_PEER_PSM_SUPPORT = 29
+    TDLS_CHANNEL_SWITCHING = 30
+    INTERWORKING = 31
+    QOS_MAP = 32
+    EBR = 33
+    SSPN_INTERFACE = 34
+    # 35 reserved
+    MSGCF_CAPABILITY = 36
+    TDLS_SUPPORT = 37
+    TDLS_PROHIBITED = 38
+    TDLS_CHANNEL_SWITCHING_PROHIBITED = 39
+    REJECT_UNADMITTED_FRAME = 40
+    SERVICE_INTERVAL_GRANULARITY = 41
+    # Bits 41-43 contain SERVICE_INTERVAL_GRANULARITY value
+    IDENTIFIER_LOCATION = 44
+    U_APSD_COEXISTENCE = 45
+    WNM_NOTIFICATION = 46
+    QAB_CAPABILITY = 47
+    UTF_8_SSID = 48
+    QMF_ACTIVATED = 49
+    QMF_RECONFIGURATION_ACTIVATED = 50
+    ROBUST_AV_STREAMING = 51
+    ADVANCED_GCR = 52
+    MESH_GCR = 53
+    SCS = 54
+    QLOAD_REPORT = 55
+    ALTERNATE_EDCA = 56
+    UNPROTECTED_TXOP_NEGOTIATION = 57
+    PROTECTED_TXOP_NEGOTIATION = 58
+    # 59 reserved
+    PROTECTED_QLOAD_REPORT = 60
+    TDLS_WIDER_BANDWIDTH = 61
+    OPERATING_MODE_NOTIFICATION = 62
+    MAX_NUMBER_OF_MSDUS_IN_A_MSDU = 63
+    # 63-64 contain MAX_NUMBER_OF_MSDUS_IN_A_MSDU value
+    CHANNEL_SCHEDULE_MANAGEMENT = 65
+    GEODATABASE_INBAND_ENABLING_SIGNAL = 66
+    NETWORK_CHANNEL_CONTROL = 67
+    WHITE_SPACE_MAP = 68
+    CHANNEL_AVAILABILITY_QUERY = 69
+    FINE_TIMING_MEASUREMENT_RESPONDER = 70
+    FINE_TIMING_MEASUREMENT_INITIATOR = 71
+    FILS_CAPABILITY = 72
+    EXTENDED_SPECTRUM_MANAGEMENT_CAPABLE = 73
+    FUTURE_CHANNEL_GUIDANCE = 74
+    PAD = 75
+    # 76-79 reserved
+    COMPLETE_LIST_OF_NON_TX_BSSID_PROFILES = 80
+    SAE_PASSWORD_IDENTIFIERS_IN_USE = 81
+    SAE_PASSWORD_IDENTIFIERS_USED_EXCLUSIVELY = 82
+    # 83 reserved
+    BEACON_PROTECTION_ENABLED = 84
+    MIRRORED_SCS = 85
+    # 86 reserved
+    LOCAL_MAC_ADDRESS_POLICY = 87
+    # 88-n reserved
+
+
+def _offsets(ext_cap_offset: ExtendedCapability) -> Tuple[int, int]:
+    """For given capability, return the byte and bit offsets within the field.
+
+    802.11 divides the extended capability field into bytes, as does the
+    ExtendedCapabilities class below. This function returns the index of the
+    byte that contains the given extended capability, as well as the bit offset
+    inside that byte (all offsets zero-indexed). For example,
+    MULTICAST_DIAGNOSTICS is bit 9, which is within byte 1 at bit offset 1.
+    """
+    byte_offset = ext_cap_offset // 8
+    bit_offset = ext_cap_offset % 8
+    return byte_offset, bit_offset
+
+
+class ExtendedCapabilities:
+    """Extended capability parsing and representation.
+
+    See IEEE 802.11-2020 9.4.2.26.
+    """
+
+    def __init__(self, ext_cap: bytearray = bytearray()):
+        """Represent the given extended capabilities field.
+
+        Args:
+            ext_cap: IEEE 802.11-2020 9.4.2.26 extended capabilities field.
+            Default is an empty field, meaning no extended capabilities are
+            advertised.
+        """
+        self._ext_cap = ext_cap
+
+    def _capability_advertised(self, ext_cap: ExtendedCapability) -> bool:
+        """Whether an extended capability is advertised.
+
+        Args:
+            ext_cap: an extended capability.
+        Returns:
+            True if the bit is present and its value is 1, otherwise False.
+        Raises:
+            NotImplementedError: for extended capabilities that span more than
+            a single bit. These could be supported, but no callers need them
+            at this time.
+        """
+        if ext_cap in [
+                ExtendedCapability.SERVICE_INTERVAL_GRANULARITY,
+                ExtendedCapability.MAX_NUMBER_OF_MSDUS_IN_A_MSDU
+        ]:
+            raise NotImplementedError(
+                f'{ext_cap.name} not implemented yet by {__class__}')
+        byte_offset, bit_offset = _offsets(ext_cap)
+        if len(self._ext_cap) > byte_offset:
+            # Use bit_offset to derive a mask that will check the correct bit.
+            if self._ext_cap[byte_offset] & 2**bit_offset > 0:
+                return True
+        return False
+
+    @property
+    def bss_transition(self) -> bool:
+        return self._capability_advertised(ExtendedCapability.BSS_TRANSITION)
+
+    @property
+    def proxy_arp_service(self) -> bool:
+        return self._capability_advertised(
+            ExtendedCapability.PROXY_ARP_SERVICE)
+
+    @property
+    def utc_tsf_offset(self) -> bool:
+        return self._capability_advertised(ExtendedCapability.UTC_TSF_OFFSET)
+
+    @property
+    def wnm_sleep_mode(self) -> bool:
+        return self._capability_advertised(ExtendedCapability.WNM_SLEEP_MODE)
+
+    # Other extended capability property methods can be added as needed by callers.
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd.py b/acts/framework/acts/controllers/ap_lib/hostapd.py
index d08caf2..c2cfc54 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd.py
@@ -15,13 +15,16 @@
 import collections
 import itertools
 import logging
-import os
 import re
 import time
+from typing import Set
 
 from acts.controllers.ap_lib import hostapd_config
 from acts.controllers.ap_lib import hostapd_constants
+from acts.controllers.ap_lib.extended_capabilities import ExtendedCapabilities
+from acts.controllers.ap_lib.wireless_network_management import BssTransitionManagementRequest
 from acts.controllers.utils_lib.commands import shell
+from acts.libs.proc.job import Result
 
 
 class Error(Exception):
@@ -137,6 +140,116 @@
             raise Error('Internal error: current channel could not be parsed')
         return channel
 
+    def _list_sta(self) -> Result:
+        """List all associated STA MAC addresses.
+
+        Returns:
+            acts.libs.proc.job.Result containing the results of the command.
+        Raises: See _run_hostapd_cli_cmd
+        """
+        list_sta_cmd = 'list_sta'
+        return self._run_hostapd_cli_cmd(list_sta_cmd)
+
+    def get_stas(self) -> Set[str]:
+        """Return MAC addresses of all associated STAs."""
+        list_sta_result = self._list_sta()
+        stas = set()
+        for line in list_sta_result.stdout.splitlines():
+            # Each line must be a valid MAC address. Capture it.
+            m = re.match(r'((?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2})', line)
+            if m:
+                stas.add(m.group(1))
+        return stas
+
+    def _sta(self, sta_mac: str) -> Result:
+        """Return hostapd's detailed info about an associated STA.
+
+        Returns:
+            acts.libs.proc.job.Result containing the results of the command.
+        Raises: See _run_hostapd_cli_cmd
+        """
+        sta_cmd = 'sta {}'.format(sta_mac)
+        return self._run_hostapd_cli_cmd(sta_cmd)
+
+    def get_sta_extended_capabilities(self,
+                                      sta_mac: str) -> ExtendedCapabilities:
+        """Get extended capabilities for the given STA, as seen by the AP.
+
+        Args:
+            sta_mac: MAC address of the STA in question.
+        Returns:
+            Extended capabilities of the given STA.
+        Raises:
+            Error if extended capabilities for the STA cannot be obtained.
+        """
+        sta_result = self._sta(sta_mac)
+        # hostapd ext_capab field is a hex encoded string representation of the
+        # 802.11 extended capabilities structure, each byte represented by two
+        # chars (each byte having format %02x).
+        m = re.search(r'ext_capab=([0-9A-Faf]+)', sta_result.stdout,
+                      re.MULTILINE)
+        if not m:
+            raise Error('Failed to get ext_capab from STA details')
+        raw_ext_capab = m.group(1)
+        try:
+            return ExtendedCapabilities(bytearray.fromhex(raw_ext_capab))
+        except ValueError:
+            raise Error(
+                f'ext_capab contains invalid hex string repr {raw_ext_capab}')
+
+    def _bss_tm_req(self, client_mac: str,
+                    request: BssTransitionManagementRequest) -> Result:
+        """Send a hostapd BSS Transition Management request command to a STA.
+
+        Args:
+            client_mac: MAC address that will receive the request.
+            request: BSS Transition Management request that will be sent.
+        Returns:
+            acts.libs.proc.job.Result containing the results of the command.
+        Raises: See _run_hostapd_cli_cmd
+        """
+        bss_tm_req_cmd = f'bss_tm_req {client_mac}'
+
+        if request.abridged:
+            bss_tm_req_cmd += ' abridged=1'
+        if request.bss_termination_included and request.bss_termination_duration:
+            bss_tm_req_cmd += f' bss_term={request.bss_termination_duration.duration}'
+        if request.disassociation_imminent:
+            bss_tm_req_cmd += ' disassoc_imminent=1'
+        if request.disassociation_timer is not None:
+            bss_tm_req_cmd += f' disassoc_timer={request.disassociation_timer}'
+        if request.preferred_candidate_list_included:
+            bss_tm_req_cmd += ' pref=1'
+        if request.session_information_url:
+            bss_tm_req_cmd += f' url={request.session_information_url}'
+        if request.validity_interval:
+            bss_tm_req_cmd += f' valid_int={request.validity_interval}'
+
+        # neighbor= can appear multiple times, so it requires special handling.
+        for neighbor in request.candidate_list:
+            bssid = neighbor.bssid
+            bssid_info = hex(neighbor.bssid_information)
+            op_class = neighbor.operating_class
+            chan_num = neighbor.channel_number
+            phy_type = int(neighbor.phy_type)
+            bss_tm_req_cmd += f' neighbor={bssid},{bssid_info},{op_class},{chan_num},{phy_type}'
+
+        return self._run_hostapd_cli_cmd(bss_tm_req_cmd)
+
+    def send_bss_transition_management_req(
+            self, sta_mac: str,
+            request: BssTransitionManagementRequest) -> Result:
+        """Send a BSS Transition Management request to an associated STA.
+
+        Args:
+            sta_mac: MAC address of the STA in question.
+            request: BSS Transition Management request that will be sent.
+        Returns:
+            acts.libs.proc.job.Result containing the results of the command.
+        Raises: See _run_hostapd_cli_cmd
+        """
+        return self._bss_tm_req(sta_mac, request)
+
     def is_alive(self):
         """
         Returns:
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py b/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
index e31fb03..62562c4 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_ap_preset.py
@@ -12,6 +12,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+from typing import FrozenSet
+
 from acts import utils
 
 import acts.controllers.ap_lib.third_party_ap_profiles.actiontec as actiontec
@@ -40,26 +42,28 @@
     return var if var is not None else default_value
 
 
-def create_ap_preset(profile_name='whirlwind',
-                     iface_wlan_2g=None,
-                     iface_wlan_5g=None,
-                     channel=None,
-                     mode=None,
-                     frequency=None,
-                     security=None,
-                     pmf_support=None,
-                     ssid=None,
-                     hidden=None,
-                     dtim_period=None,
-                     frag_threshold=None,
-                     rts_threshold=None,
-                     force_wmm=None,
-                     beacon_interval=None,
-                     short_preamble=None,
-                     n_capabilities=None,
-                     ac_capabilities=None,
-                     vht_bandwidth=None,
-                     bss_settings=[]):
+def create_ap_preset(
+        profile_name='whirlwind',
+        iface_wlan_2g=None,
+        iface_wlan_5g=None,
+        channel=None,
+        mode=None,
+        frequency=None,
+        security=None,
+        pmf_support=None,
+        ssid=None,
+        hidden=None,
+        dtim_period=None,
+        frag_threshold=None,
+        rts_threshold=None,
+        force_wmm=None,
+        beacon_interval=None,
+        short_preamble=None,
+        n_capabilities=None,
+        ac_capabilities=None,
+        vht_bandwidth=None,
+        wnm_features: FrozenSet[hostapd_constants.WnmFeature] = frozenset(),
+        bss_settings=[]):
     """AP preset config generator.  This a wrapper for hostapd_config but
        but supplies the default settings for the preset that is selected.
 
@@ -89,6 +93,7 @@
             rts/cts or cts to self.
         n_capabilities: 802.11n capabilities for for BSS to advertise.
         ac_capabilities: 802.11ac capabilities for for BSS to advertise.
+        wnm_features: WNM features to enable on the AP.
 
     Returns: A hostapd_config object that can be used by the hostapd object.
     """
@@ -141,6 +146,7 @@
                 n_capabilities=n_capabilities,
                 frag_threshold=frag_threshold,
                 rts_threshold=rts_threshold,
+                wnm_features=wnm_features,
                 bss_settings=bss_settings)
         else:
             interface = iface_wlan_5g
@@ -224,7 +230,8 @@
                                   frag_threshold=frag_threshold,
                                   n_capabilities=[],
                                   ac_capabilities=[],
-                                  vht_bandwidth=None)
+                                  vht_bandwidth=None,
+                                  wnm_features=wnm_features)
     elif profile_name == 'whirlwind_11ag_legacy':
         if frequency < 5000:
             mode = hostapd_constants.MODE_11G
@@ -247,7 +254,8 @@
                                   frag_threshold=frag_threshold,
                                   n_capabilities=[],
                                   ac_capabilities=[],
-                                  vht_bandwidth=None)
+                                  vht_bandwidth=None,
+                                  wnm_features=wnm_features)
     elif profile_name == 'mistral':
         hidden = _get_or_default(hidden, False)
         force_wmm = _get_or_default(force_wmm, True)
@@ -296,6 +304,7 @@
                 n_capabilities=n_capabilities,
                 frag_threshold=frag_threshold,
                 rts_threshold=rts_threshold,
+                wnm_features=wnm_features,
                 bss_settings=bss_settings,
                 additional_parameters=additional_params,
                 set_ap_defaults_profile=profile_name)
@@ -364,6 +373,7 @@
                 rts_threshold=rts_threshold,
                 n_capabilities=n_capabilities,
                 ac_capabilities=ac_capabilities,
+                wnm_features=wnm_features,
                 bss_settings=bss_settings,
                 additional_parameters=additional_params,
                 set_ap_defaults_profile=profile_name)
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_config.py b/acts/framework/acts/controllers/ap_lib/hostapd_config.py
index be990f7..ce508f5 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd_config.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_config.py
@@ -12,11 +12,9 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import enum
-import logging
-import os
 import collections
-import itertools
+import logging
+from typing import FrozenSet
 
 from acts.controllers.ap_lib import hostapd_constants
 
@@ -71,6 +69,7 @@
 
     All the settings for a router that are not part of an ssid.
     """
+
     def _get_11ac_center_channel_from_channel(self, channel):
         """Returns the center channel of the selected channel band based
            on the channel and channel bandwidth provided.
@@ -132,11 +131,7 @@
     @property
     def _require_ht(self):
         """Returns: True iff clients should be required to support HT."""
-        # TODO(wiley) Why? (crbug.com/237370)
-        # DOES THIS APPLY TO US?
-        logging.warning('Not enforcing pure N mode because Snow does '
-                        'not seem to support it...')
-        return False
+        return self._mode == hostapd_constants.MODE_11N_PURE
 
     @property
     def _require_vht(self):
@@ -308,6 +303,14 @@
         """Returns: int, _min_streams value, or None."""
         return self._min_streams
 
+    @property
+    def wnm_features(self) -> FrozenSet[hostapd_constants.WnmFeature]:
+        return self._wnm_features
+
+    @wnm_features.setter
+    def wnm_features(self, value: FrozenSet[hostapd_constants.WnmFeature]):
+        self._wnm_features = value
+
     def __init__(self,
                  interface=None,
                  mode=None,
@@ -333,6 +336,8 @@
                  spectrum_mgmt_required=None,
                  scenario_name=None,
                  min_streams=None,
+                 wnm_features: FrozenSet[
+                     hostapd_constants.WnmFeature] = frozenset(),
                  bss_settings=[],
                  additional_parameters={},
                  set_ap_defaults_profile='whirlwind'):
@@ -375,6 +380,7 @@
             scenario_name: string to be included in file names, instead
                 of the interface name.
             min_streams: int, number of spatial streams required.
+            wnm_features: WNM features to enable on the AP.
             control_interface: The file name to use as the control interface.
             bss_settings: The settings for all bss.
             additional_parameters: A dictionary of additional parameters to add
@@ -445,12 +451,12 @@
                 self._wmm_enabled = 0
         # Default PMF Values
         if pmf_support is None:
-            if (self.security and self.security.security_mode_string
-                    == hostapd_constants.WPA3_STRING):
+            if (self.security and self.security.security_mode_string ==
+                    hostapd_constants.WPA3_STRING):
                 # Set PMF required for WP3
                 self._pmf_support = hostapd_constants.PMF_SUPPORT_REQUIRED
-            elif (self.security and self.security.security_mode_string
-                  in hostapd_constants.WPA3_MODE_STRINGS):
+            elif (self.security and self.security.security_mode_string in
+                  hostapd_constants.WPA3_MODE_STRINGS):
                 # Default PMF to enabled for WPA3 mixed modes (can be
                 # overwritten by explicitly provided value)
                 self._pmf_support = hostapd_constants.PMF_SUPPORT_ENABLED
@@ -461,8 +467,8 @@
         elif pmf_support not in hostapd_constants.PMF_SUPPORT_VALUES:
             raise ValueError('Invalid value for pmf_support: %r' % pmf_support)
         elif (pmf_support != hostapd_constants.PMF_SUPPORT_REQUIRED
-              and self.security and self.security.security_mode_string
-              == hostapd_constants.WPA3_STRING):
+              and self.security and self.security.security_mode_string ==
+              hostapd_constants.WPA3_STRING):
             raise ValueError('PMF support must be required with wpa3.')
         else:
             self._pmf_support = pmf_support
@@ -495,6 +501,7 @@
         self._spectrum_mgmt_required = spectrum_mgmt_required
         self._scenario_name = scenario_name
         self._min_streams = min_streams
+        self._wnm_features = wnm_features
         self._additional_parameters = additional_parameters
 
         self._bss_lookup = collections.OrderedDict()
@@ -646,6 +653,22 @@
                 bss_conf[k] = v
             all_conf.append(bss_conf)
 
+        for wnm_feature in self._wnm_features:
+            if wnm_feature == hostapd_constants.WnmFeature.TIME_ADVERTISEMENT:
+                conf.update(hostapd_constants.ENABLE_WNM_TIME_ADVERTISEMENT)
+            elif wnm_feature == hostapd_constants.WnmFeature.WNM_SLEEP_MODE:
+                conf.update(hostapd_constants.ENABLE_WNM_SLEEP_MODE)
+            elif wnm_feature == hostapd_constants.WnmFeature.BSS_TRANSITION_MANAGEMENT:
+                conf.update(
+                    hostapd_constants.ENABLE_WNM_BSS_TRANSITION_MANAGEMENT)
+            elif wnm_feature == hostapd_constants.WnmFeature.PROXY_ARP:
+                conf.update(hostapd_constants.ENABLE_WNM_PROXY_ARP)
+            elif wnm_feature == hostapd_constants.WnmFeature.IPV6_NEIGHBOR_ADVERTISEMENT_MULTICAST_TO_UNICAST:
+                conf.update(
+                    hostapd_constants.
+                    ENABLE_WNM_IPV6_NEIGHBOR_ADVERTISEMENT_MULTICAST_TO_UNICAST
+                )
+
         if self._additional_parameters:
             all_conf.append(self._additional_parameters)
 
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd_constants.py b/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
index 7480257..ad3cfe8 100755
--- a/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd_constants.py
@@ -16,6 +16,8 @@
 
 import itertools
 
+from enum import Enum, auto, unique
+
 BAND_2G = '2g'
 BAND_5G = '5g'
 CHANNEL_BANDWIDTH_20MHZ = 20
@@ -535,6 +537,15 @@
 ENABLE_RRM_BEACON_REPORT = {'rrm_beacon_report': 1}
 ENABLE_RRM_NEIGHBOR_REPORT = {'rrm_neighbor_report': 1}
 
+# Wireless Network Management (AKA 802.11v) features.
+ENABLE_WNM_TIME_ADVERTISEMENT = {'time_advertisement': 2, 'time_zone': 'EST5'}
+ENABLE_WNM_SLEEP_MODE = {'wnm_sleep_mode': 1}
+ENABLE_WNM_BSS_TRANSITION_MANAGEMENT = {'bss_transition': 1}
+ENABLE_WNM_PROXY_ARP = {'proxy_arp': 1}
+ENABLE_WNM_IPV6_NEIGHBOR_ADVERTISEMENT_MULTICAST_TO_UNICAST = {
+    'na_mcast_to_ucast': 1
+}
+
 VENDOR_IE = {
     'correct_length_beacon': {
         'vendor_elements': 'dd0411223301'
@@ -1387,3 +1398,13 @@
 }
 
 ALL_CHANNELS = {**ALL_CHANNELS_2G, **ALL_CHANNELS_5G}
+
+
+@unique
+class WnmFeature(Enum):
+    """Wireless Network Management (AKA 802.11v) features hostapd supports."""
+    TIME_ADVERTISEMENT = auto()
+    WNM_SLEEP_MODE = auto()
+    BSS_TRANSITION_MANAGEMENT = auto()
+    PROXY_ARP = auto()
+    IPV6_NEIGHBOR_ADVERTISEMENT_MULTICAST_TO_UNICAST = auto()
diff --git a/acts/framework/acts/controllers/ap_lib/radio_measurement.py b/acts/framework/acts/controllers/ap_lib/radio_measurement.py
new file mode 100644
index 0000000..dc009e9
--- /dev/null
+++ b/acts/framework/acts/controllers/ap_lib/radio_measurement.py
@@ -0,0 +1,231 @@
+#!/usr/bin/env python3
+#
+#   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.
+#   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.
+
+from enum import IntEnum, unique
+
+
+@unique
+class ApReachability(IntEnum):
+    """Neighbor Report AP Reachability values.
+
+    See IEEE 802.11-2020 Figure 9-172.
+    """
+    NOT_REACHABLE = 1
+    UNKNOWN = 2
+    REACHABLE = 3
+
+
+class BssidInformationCapabilities:
+    """Representation of Neighbor Report BSSID Information Capabilities.
+
+    See IEEE 802.11-2020 Figure 9-338 and 9.4.1.4.
+    """
+
+    def __init__(self,
+                 spectrum_management: bool = False,
+                 qos: bool = False,
+                 apsd: bool = False,
+                 radio_measurement: bool = False):
+        """Create a capabilities object.
+
+        Args:
+            spectrum_management: whether spectrum management is required.
+            qos: whether QoS is implemented.
+            apsd: whether APSD is implemented.
+            radio_measurement: whether radio measurement is activated.
+        """
+        self._spectrum_management = spectrum_management
+        self._qos = qos
+        self._apsd = apsd
+        self._radio_measurement = radio_measurement
+
+    def __index__(self) -> int:
+        """Convert to numeric representation of the field's bits."""
+        return self.spectrum_management << 5 \
+            | self.qos << 4 \
+            | self.apsd << 3 \
+            | self.radio_measurement << 2
+
+    @property
+    def spectrum_management(self) -> bool:
+        return self._spectrum_management
+
+    @property
+    def qos(self) -> bool:
+        return self._qos
+
+    @property
+    def apsd(self) -> bool:
+        return self._apsd
+
+    @property
+    def radio_measurement(self) -> bool:
+        return self._radio_measurement
+
+
+class BssidInformation:
+    """Representation of Neighbor Report BSSID Information field.
+
+    BssidInformation contains info about a neighboring AP, to be included in a
+    neighbor report element. See IEEE 802.11-2020 Figure 9-337.
+    """
+
+    def __init__(self,
+                 ap_reachability: ApReachability = ApReachability.UNKNOWN,
+                 security: bool = False,
+                 key_scope: bool = False,
+                 capabilities:
+                 BssidInformationCapabilities = BssidInformationCapabilities(),
+                 mobility_domain: bool = False,
+                 high_throughput: bool = False,
+                 very_high_throughput: bool = False,
+                 ftm: bool = False):
+        """Create a BSSID Information object for a neighboring AP.
+
+        Args:
+            ap_reachability: whether this AP is reachable by the STA that
+                requested the neighbor report.
+            security: whether this AP is known to support the same security
+                provisioning as used by the STA in its current association.
+            key_scope: whether this AP is known to have the same
+                authenticator as the AP sending the report.
+            capabilities: selected capabilities of this AP.
+            mobility_domain: whether the AP is including an MDE in its beacon
+                frames and the contents of that MDE are identical to the MDE
+                advertised by the AP sending the report.
+            high_throughput: whether the AP is an HT AP including the HT
+                Capabilities element in its Beacons, and that the contents of
+                that HT capabilities element are identical to the HT
+                capabilities element advertised by the AP sending the report.
+            very_high_throughput: whether the AP is a VHT AP and the VHT
+                capabilities element, if included as a subelement, is
+                identical in content to the VHT capabilities element included
+                in the AP’s beacon.
+            ftm: whether the AP is known to have the Fine Timing Measurement
+                Responder extended capability.
+        """
+        self._ap_reachability = ap_reachability
+        self._security = security
+        self._key_scope = key_scope
+        self._capabilities = capabilities
+        self._mobility_domain = mobility_domain
+        self._high_throughput = high_throughput
+        self._very_high_throughput = very_high_throughput
+        self._ftm = ftm
+
+    def __index__(self) -> int:
+        """Convert to numeric representation of the field's bits."""
+        return self._ap_reachability << 30 \
+            | self.security << 29 \
+            | self.key_scope << 28 \
+            | int(self.capabilities) << 22 \
+            | self.mobility_domain << 21 \
+            | self.high_throughput << 20 \
+            | self.very_high_throughput << 19 \
+            | self.ftm << 18
+
+    @property
+    def security(self) -> bool:
+        return self._security
+
+    @property
+    def key_scope(self) -> bool:
+        return self._key_scope
+
+    @property
+    def capabilities(self) -> BssidInformationCapabilities:
+        return self._capabilities
+
+    @property
+    def mobility_domain(self) -> bool:
+        return self._mobility_domain
+
+    @property
+    def high_throughput(self) -> bool:
+        return self._high_throughput
+
+    @property
+    def very_high_throughput(self) -> bool:
+        return self._very_high_throughput
+
+    @property
+    def ftm(self) -> bool:
+        return self._ftm
+
+
+@unique
+class PhyType(IntEnum):
+    """PHY type values, see dot11PhyType in 802.11-2020 Annex C."""
+    DSSS = 2
+    OFDM = 4
+    HRDSS = 5
+    ERP = 6
+    HT = 7
+    DMG = 8
+    VHT = 9
+    TVHT = 10
+    S1G = 11
+    CDMG = 12
+    CMMG = 13
+
+
+class NeighborReportElement:
+    """Representation of Neighbor Report element.
+
+    See IEEE 802.11-2020 9.4.2.36.
+    """
+
+    def __init__(self, bssid: str, bssid_information: BssidInformation,
+                 operating_class: int, channel_number: int, phy_type: PhyType):
+        """Create a neighbor report element.
+
+        Args:
+            bssid: MAC address of the neighbor.
+            bssid_information: BSSID Information of the neigbor.
+            operating_class: operating class of the neighbor.
+            channel_number: channel number of the neighbor.
+            phy_type: dot11PhyType of the neighbor.
+        """
+        self._bssid = bssid
+        self._bssid_information = bssid_information
+
+        # Operating Class, IEEE 802.11-2020 Annex E.
+        self._operating_class = operating_class
+
+        self._channel_number = channel_number
+
+        # PHY Type, IEEE 802.11-2020 Annex C.
+        self._phy_type = phy_type
+
+    @property
+    def bssid(self) -> str:
+        return self._bssid
+
+    @property
+    def bssid_information(self) -> BssidInformation:
+        return self._bssid_information
+
+    @property
+    def operating_class(self) -> int:
+        return self._operating_class
+
+    @property
+    def channel_number(self) -> int:
+        return self._channel_number
+
+    @property
+    def phy_type(self) -> PhyType:
+        return self._phy_type
diff --git a/acts/framework/acts/controllers/ap_lib/radvd_config.py b/acts/framework/acts/controllers/ap_lib/radvd_config.py
index eb507cb..969d95c 100644
--- a/acts/framework/acts/controllers/ap_lib/radvd_config.py
+++ b/acts/framework/acts/controllers/ap_lib/radvd_config.py
@@ -12,6 +12,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+from acts.controllers.ap_lib import radvd_constants
+
 import collections
 
 
@@ -20,13 +22,14 @@
 
     All the settings for a router advertisement daemon.
     """
+
     def __init__(self,
-                 prefix,
+                 prefix=radvd_constants.DEFAULT_PREFIX,
                  clients=[],
                  route=None,
                  rdnss=[],
                  ignore_if_missing=None,
-                 adv_send_advert=None,
+                 adv_send_advert=radvd_constants.ADV_SEND_ADVERT_ON,
                  unicast_only=None,
                  max_rtr_adv_interval=None,
                  min_rtr_adv_interval=None,
@@ -46,8 +49,8 @@
                  home_agent_preference=None,
                  adv_mob_rtr_support_flag=None,
                  adv_interval_opt=None,
-                 adv_on_link=None,
-                 adv_autonomous=None,
+                 adv_on_link=radvd_constants.ADV_ON_LINK_ON,
+                 adv_autonomous=radvd_constants.ADV_AUTONOMOUS_ON,
                  adv_router_addr=None,
                  adv_valid_lifetime=None,
                  adv_preferred_lifetime=None,
diff --git a/acts/framework/acts/controllers/ap_lib/radvd_constants.py b/acts/framework/acts/controllers/ap_lib/radvd_constants.py
index b83ba37..a1a3e77 100644
--- a/acts/framework/acts/controllers/ap_lib/radvd_constants.py
+++ b/acts/framework/acts/controllers/ap_lib/radvd_constants.py
@@ -14,6 +14,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+DEFAULT_PREFIX = 'fd00::/64'
+
 IGNORE_IF_MISSING_ON = 'on'
 IGNORE_IF_MISSING_OFF = 'off'
 
diff --git a/acts/framework/acts/controllers/ap_lib/wireless_network_management.py b/acts/framework/acts/controllers/ap_lib/wireless_network_management.py
new file mode 100644
index 0000000..f99cd0f
--- /dev/null
+++ b/acts/framework/acts/controllers/ap_lib/wireless_network_management.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+#
+#   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.
+#   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.
+
+from typing import List, NewType, Optional
+
+from acts.controllers.ap_lib.radio_measurement import NeighborReportElement
+
+BssTransitionCandidateList = NewType('BssTransitionCandidateList',
+                                     List[NeighborReportElement])
+
+
+class BssTerminationDuration:
+    """Representation of BSS Termination Duration subelement.
+
+    See IEEE 802.11-2020 Figure 9-341.
+    """
+
+    def __init__(self, duration: int):
+        """Create a BSS Termination Duration subelement.
+
+        Args:
+            duration: number of minutes the BSS will be offline.
+        """
+        # Note: hostapd does not currently support setting BSS Termination TSF,
+        # which is the other value held in this subelement.
+        self._duration = duration
+
+    @property
+    def duration(self) -> int:
+        return self._duration
+
+
+class BssTransitionManagementRequest:
+    """Representation of BSS Transition Management request.
+
+    See IEEE 802.11-2020 9.6.13.9.
+    """
+
+    def __init__(
+            self,
+            preferred_candidate_list_included: bool = False,
+            abridged: bool = False,
+            disassociation_imminent: bool = False,
+            ess_disassociation_imminent: bool = False,
+            disassociation_timer: int = 0,
+            validity_interval: int = 1,
+            bss_termination_duration: Optional[BssTerminationDuration] = None,
+            session_information_url: Optional[str] = None,
+            candidate_list: Optional[BssTransitionCandidateList] = None):
+        """Create a BSS Transition Management request.
+
+        Args:
+            preferred_candidate_list_included: whether the candidate list is a
+                preferred candidate list, or (if False) a list of known
+                candidates.
+            abridged: whether a preference value of 0 is assigned to all BSSIDs
+                that do not appear in the candidate list, or (if False) AP has
+                no recommendation for/against anything not in the candidate
+                list.
+            disassociation_imminent: whether the STA is about to be
+                disassociated by the AP.
+            ess_disassociation_imminent: whether the STA will be disassociated
+                from the ESS.
+            disassociation_timer: the number of beacon transmission times
+                (TBTTs) until the AP disassociates this STA (default 0, meaning
+                AP has not determined when it will disassociate this STA).
+            validity_interval: number of TBTTs until the candidate list is no
+                longer valid (default 1).
+            bss_termination_duration: BSS Termination Duration subelement.
+            session_information_url: this URL is included if ESS disassociation
+                is immiment.
+            candidate_list: zero or more neighbor report elements.
+        """
+        # Request mode field, see IEEE 802.11-2020 Figure 9-924.
+        self._preferred_candidate_list_included = preferred_candidate_list_included
+        self._abridged = abridged
+        self._disassociation_imminent = disassociation_imminent
+        self._ess_disassociation_imminent = ess_disassociation_imminent
+
+        # Disassociation Timer, see IEEE 802.11-2020 Figure 9-925
+        self._disassociation_timer = disassociation_timer
+
+        # Validity Interval, see IEEE 802.11-2020 9.6.13.9
+        self._validity_interval = validity_interval
+
+        # BSS Termination Duration, see IEEE 802.11-2020 9.6.13.9 and Figure 9-341
+        self._bss_termination_duration = bss_termination_duration
+
+        # Session Information URL, see IEEE 802.11-2020 Figure 9-926
+        self._session_information_url = session_information_url
+
+        # BSS Transition Candidate List Entries, IEEE 802.11-2020 9.6.13.9.
+        self._candidate_list = candidate_list
+
+    @property
+    def preferred_candidate_list_included(self) -> bool:
+        return self._preferred_candidate_list_included
+
+    @property
+    def abridged(self) -> bool:
+        return self._abridged
+
+    @property
+    def disassociation_imminent(self) -> bool:
+        return self._disassociation_imminent
+
+    @property
+    def bss_termination_included(self) -> bool:
+        return self._bss_termination_duration is not None
+
+    @property
+    def ess_disassociation_imminent(self) -> bool:
+        return self._ess_disassociation_imminent
+
+    @property
+    def disassociation_timer(self) -> Optional[int]:
+        if self.disassociation_imminent:
+            return self._disassociation_timer
+        # Otherwise, field is reserved.
+        return None
+
+    @property
+    def validity_interval(self) -> int:
+        return self._validity_interval
+
+    @property
+    def bss_termination_duration(self) -> Optional[BssTerminationDuration]:
+        return self._bss_termination_duration
+
+    @property
+    def session_information_url(self) -> Optional[str]:
+        return self._session_information_url
+
+    @property
+    def candidate_list(self) -> Optional[BssTransitionCandidateList]:
+        return self._candidate_list
diff --git a/acts/framework/acts/controllers/attenuator.py b/acts/framework/acts/controllers/attenuator.py
index b7f4a6d..cceb857 100644
--- a/acts/framework/acts/controllers/attenuator.py
+++ b/acts/framework/acts/controllers/attenuator.py
@@ -181,7 +181,6 @@
     attenuator instrument is probably necessary. Something has gone wrong in
     the transport.
     """
-    pass
 
 
 class InvalidOperationError(AttenuatorError):
@@ -191,7 +190,6 @@
     invoked is in a certain state. This indicates that the object is not in the
     correct state for a method to be called.
     """
-    pass
 
 
 class AttenuatorInstrument(object):
diff --git a/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py b/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
index bd3d24c..62dc330 100644
--- a/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
+++ b/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
@@ -35,6 +35,7 @@
     With the exception of HTTP-specific commands, all functionality is defined
     by the AttenuatorInstrument class.
     """
+
     def __init__(self, num_atten=1):
         super(AttenuatorInstrument, self).__init__(num_atten)
         self._ip_address = None
@@ -83,7 +84,6 @@
         Since this controller is based on HTTP requests, there is no connection
         teardowns required.
         """
-        pass
 
     def set_atten(self, idx, value, strict=True, retry=False, **_):
         """This function sets the attenuation of an attenuator given its index
@@ -144,8 +144,7 @@
             raise IndexError('Attenuator index out of range!', self.num_atten,
                              idx)
         att_req = urllib.request.urlopen(
-            'http://{}:{}/CHAN:{}:ATT?'.format(self._ip_address, self.port,
-                                               idx + 1),
+            'http://{}:{}/CHAN:{}:ATT?'.format(self._ip_address, self.port, idx + 1),
             timeout=self._timeout)
         att_resp = att_req.read().decode('utf-8').strip()
         try:
diff --git a/acts/framework/acts/controllers/bits.py b/acts/framework/acts/controllers/bits.py
index d89a9b3..caadeb7 100644
--- a/acts/framework/acts/controllers/bits.py
+++ b/acts/framework/acts/controllers/bits.py
@@ -1,5 +1,7 @@
 """Module managing the required definitions for using the bits power monitor"""
 
+import csv
+import json
 import logging
 import os
 import time
@@ -424,8 +426,14 @@
         In the case where there is not enough information to retrieve a
         monsoon-like file, this function will do nothing.
         """
-        available_channels = self._client.list_channels(
-            self._active_collection.name)
+        metrics = self._client.get_metrics(self._active_collection.name)
+
+        try:
+            self._save_rails_csv(metrics)
+        except Exception as e:
+            logging.warning(
+                'Could not save rails data to csv format with error {}'.format(e))
+        available_channels = [channel['name'] for channel in metrics['data']]
         milli_amps_channel = None
 
         for channel in available_channels:
@@ -447,6 +455,70 @@
             self._active_collection.name,
             milli_amps_channel)
 
+    def _save_rails_csv(self, metrics):
+        # Creates csv path for rails data
+        monsoon_path = self._active_collection.monsoon_output_path
+        dir_path = os.path.dirname(monsoon_path)
+        if dir_path.endswith('Monsoon'):
+            dir_path = os.path.join(os.path.dirname(dir_path), 'Kibble')
+            os.makedirs(dir_path, exist_ok=True)
+        rails_basename = os.path.basename(monsoon_path)
+        if rails_basename.endswith('.txt'):
+            rails_basename = os.path.splitext(rails_basename)[0]
+        json_basename = 'kibble_rails_' + rails_basename + '.json'
+        rails_basename = 'kibble_rails_' + rails_basename + '.csv'
+        root_rail_results_basename = '{}_results.csv'.format(
+            self._root_rail.split(':')[0])
+        rails_csv_path = os.path.join(dir_path, rails_basename)
+        rails_json_path = os.path.join(dir_path, json_basename)
+        root_rail_results_path = os.path.join(dir_path, root_rail_results_basename)
+
+        logging.info('dump metric to json format: {}'.format(rails_json_path))
+        with open(rails_json_path, 'w') as f:
+            json.dump(metrics['data'], f, sort_keys=True, indent=2)
+
+        # Gets all channels
+        channels = {
+            channel['name'].split('.')[-1].split(':')[0]
+            for channel in metrics['data']
+        }
+        channels = list(channels)
+        list.sort(channels)
+
+        rail_dict = {
+            channel['name'].split('.')[-1] : channel['avg']
+            for channel in metrics['data']
+        }
+
+        root_rail_key = self._root_rail.split(':')[0] + ':mW'
+        root_rail_power = 0
+        if root_rail_key in rail_dict:
+            root_rail_power = rail_dict[root_rail_key]
+        logging.info('root rail {} power is: {}'.format(root_rail_key, root_rail_power))
+
+        path_existed = os.path.exists(root_rail_results_path)
+        with open(root_rail_results_path, 'a') as f:
+            if not path_existed:
+                f.write('{},{}'.format(root_rail_key, 'power(mW)'))
+            f.write('\n{},{}'.format(self._active_collection.name, root_rail_power))
+
+        header = ['CHANNEL', 'VALUE', 'UNIT', 'VALUE', 'UNIT', 'VALUE', 'UNIT']
+        with open(rails_csv_path, 'w') as f:
+            csvwriter = csv.writer(f)
+            csvwriter.writerow(header)
+            for key in  channels:
+                if not key.startswith('C') and not key.startswith('M'):
+                    continue
+                try:
+                    row = [key, '0', 'mA', '0', 'mV', '0', 'mW']
+                    row[1] = str(rail_dict[key + ':mA'])
+                    row[3] = str(rail_dict[key + ':mV'])
+                    row[5] = str(rail_dict[key + ':mW'])
+                    csvwriter.writerow(row)
+                    logging.debug('channel {}: {}'.format(key, row))
+                except Exception as e:
+                    logging.info('channel {} fail'.format(key))
+
     def get_waveform(self, file_path=None):
         """Parses a file generated in release_resources.
 
@@ -462,6 +534,26 @@
 
         return list(power_metrics.import_raw_data(file_path))
 
+    def get_bits_root_rail_csv_export(self, file_path=None, collection_name=None):
+        """Export raw data samples for root rail in csv format.
+
+        Args:
+            file_path: Path to save the export file.
+            collection_name: Name of collection to be exported on client.
+        """
+        if file_path is None:
+            raise ValueError('file_path cannot be None')
+        if collection_name is None:
+            raise ValueError('collection_name cannot be None')
+        try:
+            key = self._root_rail.split(':')[0] + ':mW'
+            file_name = 'raw_data_' + collection_name + '.csv'
+            raw_bits_data_path = os.path.join(file_path, file_name)
+            self._client.export_as_csv([key], collection_name,
+                                       raw_bits_data_path)
+        except Exception as e:
+            logging.warning('Failed to save raw data due to :  {}'.format(e))
+
     def teardown(self):
         if self._service is None:
             return
diff --git a/acts/framework/acts/controllers/bits_lib/bits_service_config.py b/acts/framework/acts/controllers/bits_lib/bits_service_config.py
index cb2d219..a5fb2f9 100644
--- a/acts/framework/acts/controllers/bits_lib/bits_service_config.py
+++ b/acts/framework/acts/controllers/bits_lib/bits_service_config.py
@@ -144,7 +144,11 @@
             if 'serial' not in kibble:
                 raise ValueError('An individual kibble config must have a '
                                  'serial')
-
+            if 'subkibble_params' in kibble:
+                user_defined_kibble_config = kibble['subkibble_params']
+                kibble_config = copy.deepcopy(user_defined_kibble_config)
+            else:
+                kibble_config = copy.deepcopy(DEFAULT_KIBBLE_CONFIG)
             board = kibble['board']
             connector = kibble['connector']
             serial = kibble['serial']
@@ -154,7 +158,6 @@
                 self.boards_configs[board][
                     'board_file'] = kibble_board_file
                 self.boards_configs[board]['kibble_py'] = kibble_bin
-            kibble_config = copy.deepcopy(DEFAULT_KIBBLE_CONFIG)
             kibble_config['connector'] = connector
             self.boards_configs[board]['attached_kibbles'][
                 serial] = kibble_config
diff --git a/acts/framework/acts/controllers/bluetooth_pts_device.py b/acts/framework/acts/controllers/bluetooth_pts_device.py
index 917c1e4..f321141 100644
--- a/acts/framework/acts/controllers/bluetooth_pts_device.py
+++ b/acts/framework/acts/controllers/bluetooth_pts_device.py
@@ -47,7 +47,6 @@
 """
 from acts import signals
 from datetime import datetime
-from threading import Thread
 
 import ctypes
 import logging
diff --git a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/apollo_qa_pb2.py b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/apollo_qa_pb2.py
index 8bfbda9..1290491 100644
--- a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/apollo_qa_pb2.py
+++ b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/apollo_qa_pb2.py
@@ -1,807 +1,59 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: apollo_qa.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
+from google.protobuf import descriptor_pool as _descriptor_pool
 from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
 # @@protoc_insertion_point(imports)
 
 _sym_db = _symbol_database.Default()
 
 
-import acts.controllers.buds_lib.dev_utils.proto.gen.nanopb_pb2 as nanopb__pb2
+from . import nanopb_pb2 as nanopb__pb2
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='apollo_qa.proto',
-  package='apollo.lib.apollo_dev_util_lib.proto',
-  syntax='proto2',
-  serialized_pb=_b('\n\x0f\x61pollo_qa.proto\x12$apollo.lib.apollo_dev_util_lib.proto\x1a\x0cnanopb.proto\"t\n\rApolloQATrace\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x39\n\x02id\x18\x02 \x02(\x0e\x32-.apollo.lib.apollo_dev_util_lib.proto.TraceId\x12\x15\n\x04\x64\x61ta\x18\x03 \x03(\rB\x07\x10\x01\x92?\x02\x10\x05\"\xcd\x02\n\x16\x41polloQAGetVerResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x16\n\x0e\x63sr_fw_version\x18\x02 \x02(\r\x12\x1a\n\x12\x63sr_fw_debug_build\x18\x03 \x02(\x08\x12\x17\n\x0fvm_build_number\x18\x04 \x02(\r\x12\x16\n\x0evm_debug_build\x18\x05 \x02(\x08\x12\x14\n\x0cpsoc_version\x18\x06 \x02(\r\x12\x1a\n\x0b\x62uild_label\x18\x07 \x02(\tB\x05\x92?\x02\x08 \x12Q\n\x0flast_ota_status\x18\x08 \x01(\x0e\x32\x38.apollo.lib.apollo_dev_util_lib.proto.PreviousBootStatus\x12\x17\n\x0f\x63harger_version\x18\t \x02(\r\x12\x1d\n\x15\x65xpected_psoc_version\x18\n \x01(\r\"u\n\x18\x41polloQAGetCodecResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x46\n\x05\x63odec\x18\x02 \x01(\x0e\x32\x37.apollo.lib.apollo_dev_util_lib.proto.ApolloQAA2dpCodec\"\xa6\x01\n\x1c\x41polloQAGetDspStatusResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x15\n\ris_dsp_loaded\x18\x02 \x02(\x08\x12\x43\n\nsink_state\x18\x03 \x02(\x0e\x32/.apollo.lib.apollo_dev_util_lib.proto.SinkState\x12\x17\n\x0f\x66\x65\x61tures_active\x18\x04 \x02(\r\"\xb9\x01\n\x18\x41polloQAFactoryPlaySound\x12Y\n\x06prompt\x18\x01 \x02(\x0e\x32I.apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound.PromptType\"B\n\nPromptType\x12\x1c\n\x18PROMPT_TYPE_BT_CONNECTED\x10\x01\x12\x16\n\x12PROMPT_TYPE_IN_EAR\x10\x02\"\x1c\n\x1a\x41polloQAFactoryInfoRequest\"\xb6\x01\n\x1b\x41polloQAFactoryInfoResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x1b\n\x0c\x63rystal_trim\x18\x02 \x01(\x05\x42\x05\x92?\x02\x38\x10\x12\x19\n\x11\x63rash_dump_exists\x18\x03 \x01(\x08\x12!\n\x19is_developer_mode_enabled\x18\x04 \x01(\x08\x12\x1b\n\x13is_always_connected\x18\x05 \x01(\x08\x12\x0c\n\x04hwid\x18\x06 \x01(\r*\xb8\x01\n\x13\x41polloQAMessageType\x12\t\n\x05TRACE\x10\x01\x12\x14\n\x10GET_VER_RESPONSE\x10\x02\x12\x16\n\x12GET_CODEC_RESPONSE\x10\x03\x12\x1b\n\x17GET_DSP_STATUS_RESPONSE\x10\x04\x12\x16\n\x12\x46\x41\x43TORY_PLAY_SOUND\x10\x05\x12\x18\n\x14\x46\x41\x43TORY_INFO_REQUEST\x10\x06\x12\x19\n\x15\x46\x41\x43TORY_INFO_RESPONSE\x10\x07*\xfc\x02\n\x07TraceId\x12\x17\n\x13OTA_ERASE_PARTITION\x10\x01\x12\x1d\n\x19OTA_START_PARTITION_WRITE\x10\x02\x12 \n\x1cOTA_FINISHED_PARTITION_WRITE\x10\x03\x12\x17\n\x13OTA_SIGNATURE_START\x10\x04\x12\x19\n\x15OTA_SIGNATURE_FAILURE\x10\x05\x12\x19\n\x15OTA_TRIGGERING_LOADER\x10\x06\x12\x1c\n\x18OTA_LOADER_VERIFY_FAILED\x10\x07\x12\x10\n\x0cOTA_PROGRESS\x10\x08\x12\x0f\n\x0bOTA_ABORTED\x10\t\x12\x1c\n\x18\x41VRCP_PLAY_STATUS_CHANGE\x10\n\x12\x11\n\rVOLUME_CHANGE\x10\x0b\x12\x1a\n\x16\x43OMMANDER_RECV_COMMAND\x10\x0c\x12\x1c\n\x18\x43OMMANDER_FINISH_COMMAND\x10\r\x12\x1c\n\x18\x43OMMANDER_REJECT_COMMAND\x10\x0e*m\n\x0f\x41vrcpPlayStatus\x12\x0b\n\x07STOPPED\x10\x00\x12\x0b\n\x07PLAYING\x10\x01\x12\n\n\x06PAUSED\x10\x02\x12\x0c\n\x08\x46WD_SEEK\x10\x08\x12\x0c\n\x08REV_SEEK\x10\x10\x12\t\n\x05\x45RROR\x10\x05\x12\r\n\tSEEK_MASK\x10\x18*4\n\x12PreviousBootStatus\x12\x0f\n\x0bOTA_SUCCESS\x10\x01\x12\r\n\tOTA_ERROR\x10\x02*%\n\x11\x41polloQAA2dpCodec\x12\x07\n\x03\x41\x41\x43\x10\x01\x12\x07\n\x03SBC\x10\x02*\xd8\x02\n\tSinkState\x12\t\n\x05LIMBO\x10\x00\x12\x0f\n\x0b\x43ONNECTABLE\x10\x01\x12\x10\n\x0c\x44ISCOVERABLE\x10\x02\x12\r\n\tCONNECTED\x10\x03\x12\x1c\n\x18OUTGOING_CALLS_ESTABLISH\x10\x04\x12\x1c\n\x18INCOMING_CALLS_ESTABLISH\x10\x05\x12\x13\n\x0f\x41\x43TIVE_CALL_SCO\x10\x06\x12\r\n\tTEST_MODE\x10\x07\x12\x1a\n\x16THREE_WAY_CALL_WAITING\x10\x08\x12\x1a\n\x16THREE_WAY_CALL_ON_HOLD\x10\t\x12\x17\n\x13THREE_WAY_MULTICALL\x10\n\x12\x19\n\x15INCOMING_CALL_ON_HOLD\x10\x0b\x12\x16\n\x12\x41\x43TIVE_CALL_NO_SCO\x10\x0c\x12\x12\n\x0e\x41\x32\x44P_STREAMING\x10\r\x12\x16\n\x12\x44\x45VICE_LOW_BATTERY\x10\x0e\x42)\n\x1d\x63om.google.android.bisto.nanoB\x08\x41polloQA')
-  ,
-  dependencies=[nanopb__pb2.DESCRIPTOR,])
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x61pollo_qa.proto\x12$apollo.lib.apollo_dev_util_lib.proto\x1a\x0cnanopb.proto\"t\n\rApolloQATrace\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x39\n\x02id\x18\x02 \x02(\x0e\x32-.apollo.lib.apollo_dev_util_lib.proto.TraceId\x12\x15\n\x04\x64\x61ta\x18\x03 \x03(\rB\x07\x10\x01\x92?\x02\x10\x05\"\xcd\x02\n\x16\x41polloQAGetVerResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x16\n\x0e\x63sr_fw_version\x18\x02 \x02(\r\x12\x1a\n\x12\x63sr_fw_debug_build\x18\x03 \x02(\x08\x12\x17\n\x0fvm_build_number\x18\x04 \x02(\r\x12\x16\n\x0evm_debug_build\x18\x05 \x02(\x08\x12\x14\n\x0cpsoc_version\x18\x06 \x02(\r\x12\x1a\n\x0b\x62uild_label\x18\x07 \x02(\tB\x05\x92?\x02\x08 \x12Q\n\x0flast_ota_status\x18\x08 \x01(\x0e\x32\x38.apollo.lib.apollo_dev_util_lib.proto.PreviousBootStatus\x12\x17\n\x0f\x63harger_version\x18\t \x02(\r\x12\x1d\n\x15\x65xpected_psoc_version\x18\n \x01(\r\"u\n\x18\x41polloQAGetCodecResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x46\n\x05\x63odec\x18\x02 \x01(\x0e\x32\x37.apollo.lib.apollo_dev_util_lib.proto.ApolloQAA2dpCodec\"\xa6\x01\n\x1c\x41polloQAGetDspStatusResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x15\n\ris_dsp_loaded\x18\x02 \x02(\x08\x12\x43\n\nsink_state\x18\x03 \x02(\x0e\x32/.apollo.lib.apollo_dev_util_lib.proto.SinkState\x12\x17\n\x0f\x66\x65\x61tures_active\x18\x04 \x02(\r\"\xb9\x01\n\x18\x41polloQAFactoryPlaySound\x12Y\n\x06prompt\x18\x01 \x02(\x0e\x32I.apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound.PromptType\"B\n\nPromptType\x12\x1c\n\x18PROMPT_TYPE_BT_CONNECTED\x10\x01\x12\x16\n\x12PROMPT_TYPE_IN_EAR\x10\x02\"\x1c\n\x1a\x41polloQAFactoryInfoRequest\"\xb6\x01\n\x1b\x41polloQAFactoryInfoResponse\x12\x11\n\ttimestamp\x18\x01 \x02(\r\x12\x1b\n\x0c\x63rystal_trim\x18\x02 \x01(\x05\x42\x05\x92?\x02\x38\x10\x12\x19\n\x11\x63rash_dump_exists\x18\x03 \x01(\x08\x12!\n\x19is_developer_mode_enabled\x18\x04 \x01(\x08\x12\x1b\n\x13is_always_connected\x18\x05 \x01(\x08\x12\x0c\n\x04hwid\x18\x06 \x01(\r*\xb8\x01\n\x13\x41polloQAMessageType\x12\t\n\x05TRACE\x10\x01\x12\x14\n\x10GET_VER_RESPONSE\x10\x02\x12\x16\n\x12GET_CODEC_RESPONSE\x10\x03\x12\x1b\n\x17GET_DSP_STATUS_RESPONSE\x10\x04\x12\x16\n\x12\x46\x41\x43TORY_PLAY_SOUND\x10\x05\x12\x18\n\x14\x46\x41\x43TORY_INFO_REQUEST\x10\x06\x12\x19\n\x15\x46\x41\x43TORY_INFO_RESPONSE\x10\x07*\xfc\x02\n\x07TraceId\x12\x17\n\x13OTA_ERASE_PARTITION\x10\x01\x12\x1d\n\x19OTA_START_PARTITION_WRITE\x10\x02\x12 \n\x1cOTA_FINISHED_PARTITION_WRITE\x10\x03\x12\x17\n\x13OTA_SIGNATURE_START\x10\x04\x12\x19\n\x15OTA_SIGNATURE_FAILURE\x10\x05\x12\x19\n\x15OTA_TRIGGERING_LOADER\x10\x06\x12\x1c\n\x18OTA_LOADER_VERIFY_FAILED\x10\x07\x12\x10\n\x0cOTA_PROGRESS\x10\x08\x12\x0f\n\x0bOTA_ABORTED\x10\t\x12\x1c\n\x18\x41VRCP_PLAY_STATUS_CHANGE\x10\n\x12\x11\n\rVOLUME_CHANGE\x10\x0b\x12\x1a\n\x16\x43OMMANDER_RECV_COMMAND\x10\x0c\x12\x1c\n\x18\x43OMMANDER_FINISH_COMMAND\x10\r\x12\x1c\n\x18\x43OMMANDER_REJECT_COMMAND\x10\x0e*m\n\x0f\x41vrcpPlayStatus\x12\x0b\n\x07STOPPED\x10\x00\x12\x0b\n\x07PLAYING\x10\x01\x12\n\n\x06PAUSED\x10\x02\x12\x0c\n\x08\x46WD_SEEK\x10\x08\x12\x0c\n\x08REV_SEEK\x10\x10\x12\t\n\x05\x45RROR\x10\x05\x12\r\n\tSEEK_MASK\x10\x18*4\n\x12PreviousBootStatus\x12\x0f\n\x0bOTA_SUCCESS\x10\x01\x12\r\n\tOTA_ERROR\x10\x02*%\n\x11\x41polloQAA2dpCodec\x12\x07\n\x03\x41\x41\x43\x10\x01\x12\x07\n\x03SBC\x10\x02*\xd8\x02\n\tSinkState\x12\t\n\x05LIMBO\x10\x00\x12\x0f\n\x0b\x43ONNECTABLE\x10\x01\x12\x10\n\x0c\x44ISCOVERABLE\x10\x02\x12\r\n\tCONNECTED\x10\x03\x12\x1c\n\x18OUTGOING_CALLS_ESTABLISH\x10\x04\x12\x1c\n\x18INCOMING_CALLS_ESTABLISH\x10\x05\x12\x13\n\x0f\x41\x43TIVE_CALL_SCO\x10\x06\x12\r\n\tTEST_MODE\x10\x07\x12\x1a\n\x16THREE_WAY_CALL_WAITING\x10\x08\x12\x1a\n\x16THREE_WAY_CALL_ON_HOLD\x10\t\x12\x17\n\x13THREE_WAY_MULTICALL\x10\n\x12\x19\n\x15INCOMING_CALL_ON_HOLD\x10\x0b\x12\x16\n\x12\x41\x43TIVE_CALL_NO_SCO\x10\x0c\x12\x12\n\x0e\x41\x32\x44P_STREAMING\x10\r\x12\x16\n\x12\x44\x45VICE_LOW_BATTERY\x10\x0e\x42)\n\x1d\x63om.google.android.bisto.nanoB\x08\x41polloQA')
 
-_APOLLOQAMESSAGETYPE = _descriptor.EnumDescriptor(
-  name='ApolloQAMessageType',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAMessageType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='TRACE', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='GET_VER_RESPONSE', index=1, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='GET_CODEC_RESPONSE', index=2, number=3,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='GET_DSP_STATUS_RESPONSE', index=3, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FACTORY_PLAY_SOUND', index=4, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FACTORY_INFO_REQUEST', index=5, number=6,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FACTORY_INFO_RESPONSE', index=6, number=7,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1217,
-  serialized_end=1401,
-)
-_sym_db.RegisterEnumDescriptor(_APOLLOQAMESSAGETYPE)
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'apollo_qa_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
 
-ApolloQAMessageType = enum_type_wrapper.EnumTypeWrapper(_APOLLOQAMESSAGETYPE)
-_TRACEID = _descriptor.EnumDescriptor(
-  name='TraceId',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.TraceId',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='OTA_ERASE_PARTITION', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_START_PARTITION_WRITE', index=1, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_FINISHED_PARTITION_WRITE', index=2, number=3,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_SIGNATURE_START', index=3, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_SIGNATURE_FAILURE', index=4, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_TRIGGERING_LOADER', index=5, number=6,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_LOADER_VERIFY_FAILED', index=6, number=7,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_PROGRESS', index=7, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_ABORTED', index=8, number=9,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='AVRCP_PLAY_STATUS_CHANGE', index=9, number=10,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='VOLUME_CHANGE', index=10, number=11,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='COMMANDER_RECV_COMMAND', index=11, number=12,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='COMMANDER_FINISH_COMMAND', index=12, number=13,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='COMMANDER_REJECT_COMMAND', index=13, number=14,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1404,
-  serialized_end=1784,
-)
-_sym_db.RegisterEnumDescriptor(_TRACEID)
-
-TraceId = enum_type_wrapper.EnumTypeWrapper(_TRACEID)
-_AVRCPPLAYSTATUS = _descriptor.EnumDescriptor(
-  name='AvrcpPlayStatus',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.AvrcpPlayStatus',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='STOPPED', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='PLAYING', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='PAUSED', index=2, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FWD_SEEK', index=3, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='REV_SEEK', index=4, number=16,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='ERROR', index=5, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='SEEK_MASK', index=6, number=24,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1786,
-  serialized_end=1895,
-)
-_sym_db.RegisterEnumDescriptor(_AVRCPPLAYSTATUS)
-
-AvrcpPlayStatus = enum_type_wrapper.EnumTypeWrapper(_AVRCPPLAYSTATUS)
-_PREVIOUSBOOTSTATUS = _descriptor.EnumDescriptor(
-  name='PreviousBootStatus',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.PreviousBootStatus',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='OTA_SUCCESS', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA_ERROR', index=1, number=2,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1897,
-  serialized_end=1949,
-)
-_sym_db.RegisterEnumDescriptor(_PREVIOUSBOOTSTATUS)
-
-PreviousBootStatus = enum_type_wrapper.EnumTypeWrapper(_PREVIOUSBOOTSTATUS)
-_APOLLOQAA2DPCODEC = _descriptor.EnumDescriptor(
-  name='ApolloQAA2dpCodec',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAA2dpCodec',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='AAC', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='SBC', index=1, number=2,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1951,
-  serialized_end=1988,
-)
-_sym_db.RegisterEnumDescriptor(_APOLLOQAA2DPCODEC)
-
-ApolloQAA2dpCodec = enum_type_wrapper.EnumTypeWrapper(_APOLLOQAA2DPCODEC)
-_SINKSTATE = _descriptor.EnumDescriptor(
-  name='SinkState',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.SinkState',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='LIMBO', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CONNECTABLE', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DISCOVERABLE', index=2, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CONNECTED', index=3, number=3,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OUTGOING_CALLS_ESTABLISH', index=4, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='INCOMING_CALLS_ESTABLISH', index=5, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='ACTIVE_CALL_SCO', index=6, number=6,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TEST_MODE', index=7, number=7,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='THREE_WAY_CALL_WAITING', index=8, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='THREE_WAY_CALL_ON_HOLD', index=9, number=9,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='THREE_WAY_MULTICALL', index=10, number=10,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='INCOMING_CALL_ON_HOLD', index=11, number=11,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='ACTIVE_CALL_NO_SCO', index=12, number=12,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='A2DP_STREAMING', index=13, number=13,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DEVICE_LOW_BATTERY', index=14, number=14,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1991,
-  serialized_end=2335,
-)
-_sym_db.RegisterEnumDescriptor(_SINKSTATE)
-
-SinkState = enum_type_wrapper.EnumTypeWrapper(_SINKSTATE)
-TRACE = 1
-GET_VER_RESPONSE = 2
-GET_CODEC_RESPONSE = 3
-GET_DSP_STATUS_RESPONSE = 4
-FACTORY_PLAY_SOUND = 5
-FACTORY_INFO_REQUEST = 6
-FACTORY_INFO_RESPONSE = 7
-OTA_ERASE_PARTITION = 1
-OTA_START_PARTITION_WRITE = 2
-OTA_FINISHED_PARTITION_WRITE = 3
-OTA_SIGNATURE_START = 4
-OTA_SIGNATURE_FAILURE = 5
-OTA_TRIGGERING_LOADER = 6
-OTA_LOADER_VERIFY_FAILED = 7
-OTA_PROGRESS = 8
-OTA_ABORTED = 9
-AVRCP_PLAY_STATUS_CHANGE = 10
-VOLUME_CHANGE = 11
-COMMANDER_RECV_COMMAND = 12
-COMMANDER_FINISH_COMMAND = 13
-COMMANDER_REJECT_COMMAND = 14
-STOPPED = 0
-PLAYING = 1
-PAUSED = 2
-FWD_SEEK = 8
-REV_SEEK = 16
-ERROR = 5
-SEEK_MASK = 24
-OTA_SUCCESS = 1
-OTA_ERROR = 2
-AAC = 1
-SBC = 2
-LIMBO = 0
-CONNECTABLE = 1
-DISCOVERABLE = 2
-CONNECTED = 3
-OUTGOING_CALLS_ESTABLISH = 4
-INCOMING_CALLS_ESTABLISH = 5
-ACTIVE_CALL_SCO = 6
-TEST_MODE = 7
-THREE_WAY_CALL_WAITING = 8
-THREE_WAY_CALL_ON_HOLD = 9
-THREE_WAY_MULTICALL = 10
-INCOMING_CALL_ON_HOLD = 11
-ACTIVE_CALL_NO_SCO = 12
-A2DP_STREAMING = 13
-DEVICE_LOW_BATTERY = 14
-
-
-_APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE = _descriptor.EnumDescriptor(
-  name='PromptType',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound.PromptType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='PROMPT_TYPE_BT_CONNECTED', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='PROMPT_TYPE_IN_EAR', index=1, number=2,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=933,
-  serialized_end=999,
-)
-_sym_db.RegisterEnumDescriptor(_APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE)
-
-
-_APOLLOQATRACE = _descriptor.Descriptor(
-  name='ApolloQATrace',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQATrace',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='timestamp', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQATrace.timestamp', index=0,
-      number=1, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='id', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQATrace.id', index=1,
-      number=2, type=14, cpp_type=8, label=2,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='data', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQATrace.data', index=2,
-      number=3, type=13, cpp_type=3, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\020\001\222?\002\020\005'))),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=71,
-  serialized_end=187,
-)
-
-
-_APOLLOQAGETVERRESPONSE = _descriptor.Descriptor(
-  name='ApolloQAGetVerResponse',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='timestamp', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.timestamp', index=0,
-      number=1, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='csr_fw_version', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.csr_fw_version', index=1,
-      number=2, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='csr_fw_debug_build', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.csr_fw_debug_build', index=2,
-      number=3, type=8, cpp_type=7, label=2,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='vm_build_number', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.vm_build_number', index=3,
-      number=4, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='vm_debug_build', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.vm_debug_build', index=4,
-      number=5, type=8, cpp_type=7, label=2,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='psoc_version', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.psoc_version', index=5,
-      number=6, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='build_label', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.build_label', index=6,
-      number=7, type=9, cpp_type=9, label=2,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\222?\002\010 '))),
-    _descriptor.FieldDescriptor(
-      name='last_ota_status', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.last_ota_status', index=7,
-      number=8, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='charger_version', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.charger_version', index=8,
-      number=9, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='expected_psoc_version', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse.expected_psoc_version', index=9,
-      number=10, type=13, cpp_type=3, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=190,
-  serialized_end=523,
-)
-
-
-_APOLLOQAGETCODECRESPONSE = _descriptor.Descriptor(
-  name='ApolloQAGetCodecResponse',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetCodecResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='timestamp', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetCodecResponse.timestamp', index=0,
-      number=1, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='codec', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetCodecResponse.codec', index=1,
-      number=2, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=525,
-  serialized_end=642,
-)
-
-
-_APOLLOQAGETDSPSTATUSRESPONSE = _descriptor.Descriptor(
-  name='ApolloQAGetDspStatusResponse',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='timestamp', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse.timestamp', index=0,
-      number=1, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='is_dsp_loaded', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse.is_dsp_loaded', index=1,
-      number=2, type=8, cpp_type=7, label=2,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='sink_state', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse.sink_state', index=2,
-      number=3, type=14, cpp_type=8, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='features_active', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse.features_active', index=3,
-      number=4, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=645,
-  serialized_end=811,
-)
-
-
-_APOLLOQAFACTORYPLAYSOUND = _descriptor.Descriptor(
-  name='ApolloQAFactoryPlaySound',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='prompt', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound.prompt', index=0,
-      number=1, type=14, cpp_type=8, label=2,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-    _APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE,
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=814,
-  serialized_end=999,
-)
-
-
-_APOLLOQAFACTORYINFOREQUEST = _descriptor.Descriptor(
-  name='ApolloQAFactoryInfoRequest',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1001,
-  serialized_end=1029,
-)
-
-
-_APOLLOQAFACTORYINFORESPONSE = _descriptor.Descriptor(
-  name='ApolloQAFactoryInfoResponse',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='timestamp', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.timestamp', index=0,
-      number=1, type=13, cpp_type=3, label=2,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='crystal_trim', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.crystal_trim', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\222?\0028\020'))),
-    _descriptor.FieldDescriptor(
-      name='crash_dump_exists', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.crash_dump_exists', index=2,
-      number=3, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='is_developer_mode_enabled', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.is_developer_mode_enabled', index=3,
-      number=4, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='is_always_connected', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.is_always_connected', index=4,
-      number=5, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='hwid', full_name='apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse.hwid', index=5,
-      number=6, type=13, cpp_type=3, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1032,
-  serialized_end=1214,
-)
-
-_APOLLOQATRACE.fields_by_name['id'].enum_type = _TRACEID
-_APOLLOQAGETVERRESPONSE.fields_by_name['last_ota_status'].enum_type = _PREVIOUSBOOTSTATUS
-_APOLLOQAGETCODECRESPONSE.fields_by_name['codec'].enum_type = _APOLLOQAA2DPCODEC
-_APOLLOQAGETDSPSTATUSRESPONSE.fields_by_name['sink_state'].enum_type = _SINKSTATE
-_APOLLOQAFACTORYPLAYSOUND.fields_by_name['prompt'].enum_type = _APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE
-_APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE.containing_type = _APOLLOQAFACTORYPLAYSOUND
-DESCRIPTOR.message_types_by_name['ApolloQATrace'] = _APOLLOQATRACE
-DESCRIPTOR.message_types_by_name['ApolloQAGetVerResponse'] = _APOLLOQAGETVERRESPONSE
-DESCRIPTOR.message_types_by_name['ApolloQAGetCodecResponse'] = _APOLLOQAGETCODECRESPONSE
-DESCRIPTOR.message_types_by_name['ApolloQAGetDspStatusResponse'] = _APOLLOQAGETDSPSTATUSRESPONSE
-DESCRIPTOR.message_types_by_name['ApolloQAFactoryPlaySound'] = _APOLLOQAFACTORYPLAYSOUND
-DESCRIPTOR.message_types_by_name['ApolloQAFactoryInfoRequest'] = _APOLLOQAFACTORYINFOREQUEST
-DESCRIPTOR.message_types_by_name['ApolloQAFactoryInfoResponse'] = _APOLLOQAFACTORYINFORESPONSE
-DESCRIPTOR.enum_types_by_name['ApolloQAMessageType'] = _APOLLOQAMESSAGETYPE
-DESCRIPTOR.enum_types_by_name['TraceId'] = _TRACEID
-DESCRIPTOR.enum_types_by_name['AvrcpPlayStatus'] = _AVRCPPLAYSTATUS
-DESCRIPTOR.enum_types_by_name['PreviousBootStatus'] = _PREVIOUSBOOTSTATUS
-DESCRIPTOR.enum_types_by_name['ApolloQAA2dpCodec'] = _APOLLOQAA2DPCODEC
-DESCRIPTOR.enum_types_by_name['SinkState'] = _SINKSTATE
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-ApolloQATrace = _reflection.GeneratedProtocolMessageType('ApolloQATrace', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQATRACE,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQATrace)
-  ))
-_sym_db.RegisterMessage(ApolloQATrace)
-
-ApolloQAGetVerResponse = _reflection.GeneratedProtocolMessageType('ApolloQAGetVerResponse', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAGETVERRESPONSE,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetVerResponse)
-  ))
-_sym_db.RegisterMessage(ApolloQAGetVerResponse)
-
-ApolloQAGetCodecResponse = _reflection.GeneratedProtocolMessageType('ApolloQAGetCodecResponse', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAGETCODECRESPONSE,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetCodecResponse)
-  ))
-_sym_db.RegisterMessage(ApolloQAGetCodecResponse)
-
-ApolloQAGetDspStatusResponse = _reflection.GeneratedProtocolMessageType('ApolloQAGetDspStatusResponse', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAGETDSPSTATUSRESPONSE,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAGetDspStatusResponse)
-  ))
-_sym_db.RegisterMessage(ApolloQAGetDspStatusResponse)
-
-ApolloQAFactoryPlaySound = _reflection.GeneratedProtocolMessageType('ApolloQAFactoryPlaySound', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAFACTORYPLAYSOUND,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryPlaySound)
-  ))
-_sym_db.RegisterMessage(ApolloQAFactoryPlaySound)
-
-ApolloQAFactoryInfoRequest = _reflection.GeneratedProtocolMessageType('ApolloQAFactoryInfoRequest', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAFACTORYINFOREQUEST,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoRequest)
-  ))
-_sym_db.RegisterMessage(ApolloQAFactoryInfoRequest)
-
-ApolloQAFactoryInfoResponse = _reflection.GeneratedProtocolMessageType('ApolloQAFactoryInfoResponse', (_message.Message,), dict(
-  DESCRIPTOR = _APOLLOQAFACTORYINFORESPONSE,
-  __module__ = 'apollo_qa_pb2'
-  # @@protoc_insertion_point(class_scope:apollo.lib.apollo_dev_util_lib.proto.ApolloQAFactoryInfoResponse)
-  ))
-_sym_db.RegisterMessage(ApolloQAFactoryInfoResponse)
-
-
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\035com.google.android.bisto.nanoB\010ApolloQA'))
-_APOLLOQATRACE.fields_by_name['data'].has_options = True
-_APOLLOQATRACE.fields_by_name['data']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\020\001\222?\002\020\005'))
-_APOLLOQAGETVERRESPONSE.fields_by_name['build_label'].has_options = True
-_APOLLOQAGETVERRESPONSE.fields_by_name['build_label']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\222?\002\010 '))
-_APOLLOQAFACTORYINFORESPONSE.fields_by_name['crystal_trim'].has_options = True
-_APOLLOQAFACTORYINFORESPONSE.fields_by_name['crystal_trim']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\222?\0028\020'))
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n\035com.google.android.bisto.nanoB\010ApolloQA'
+  _APOLLOQATRACE.fields_by_name['data']._options = None
+  _APOLLOQATRACE.fields_by_name['data']._serialized_options = b'\020\001\222?\002\020\005'
+  _APOLLOQAGETVERRESPONSE.fields_by_name['build_label']._options = None
+  _APOLLOQAGETVERRESPONSE.fields_by_name['build_label']._serialized_options = b'\222?\002\010 '
+  _APOLLOQAFACTORYINFORESPONSE.fields_by_name['crystal_trim']._options = None
+  _APOLLOQAFACTORYINFORESPONSE.fields_by_name['crystal_trim']._serialized_options = b'\222?\0028\020'
+  _APOLLOQAMESSAGETYPE._serialized_start=1217
+  _APOLLOQAMESSAGETYPE._serialized_end=1401
+  _TRACEID._serialized_start=1404
+  _TRACEID._serialized_end=1784
+  _AVRCPPLAYSTATUS._serialized_start=1786
+  _AVRCPPLAYSTATUS._serialized_end=1895
+  _PREVIOUSBOOTSTATUS._serialized_start=1897
+  _PREVIOUSBOOTSTATUS._serialized_end=1949
+  _APOLLOQAA2DPCODEC._serialized_start=1951
+  _APOLLOQAA2DPCODEC._serialized_end=1988
+  _SINKSTATE._serialized_start=1991
+  _SINKSTATE._serialized_end=2335
+  _APOLLOQATRACE._serialized_start=71
+  _APOLLOQATRACE._serialized_end=187
+  _APOLLOQAGETVERRESPONSE._serialized_start=190
+  _APOLLOQAGETVERRESPONSE._serialized_end=523
+  _APOLLOQAGETCODECRESPONSE._serialized_start=525
+  _APOLLOQAGETCODECRESPONSE._serialized_end=642
+  _APOLLOQAGETDSPSTATUSRESPONSE._serialized_start=645
+  _APOLLOQAGETDSPSTATUSRESPONSE._serialized_end=811
+  _APOLLOQAFACTORYPLAYSOUND._serialized_start=814
+  _APOLLOQAFACTORYPLAYSOUND._serialized_end=999
+  _APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE._serialized_start=933
+  _APOLLOQAFACTORYPLAYSOUND_PROMPTTYPE._serialized_end=999
+  _APOLLOQAFACTORYINFOREQUEST._serialized_start=1001
+  _APOLLOQAFACTORYINFOREQUEST._serialized_end=1029
+  _APOLLOQAFACTORYINFORESPONSE._serialized_start=1032
+  _APOLLOQAFACTORYINFORESPONSE._serialized_end=1214
 # @@protoc_insertion_point(module_scope)
diff --git a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/audiowear_pb2.py b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/audiowear_pb2.py
index 094a868..123a079 100644
--- a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/audiowear_pb2.py
+++ b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/audiowear_pb2.py
@@ -1,14 +1,11 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: audiowear.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
+from google.protobuf import descriptor_pool as _descriptor_pool
 from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
 # @@protoc_insertion_point(imports)
 
 _sym_db = _symbol_database.Default()
@@ -16,109 +13,14 @@
 
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='audiowear.proto',
-  package='apollo.lib.apollo_dev_util_lib.proto',
-  syntax='proto2',
-  serialized_pb=_b('\n\x0f\x61udiowear.proto\x12$apollo.lib.apollo_dev_util_lib.proto*\x8d\x02\n\x0cMessageGroup\x12\x19\n\x15UNKNOWN_MESSAGE_GROUP\x10\x00\x12\x10\n\x0c\x44\x45VICE_INPUT\x10\x01\x12\x07\n\x03OTA\x10\x02\x12\x15\n\x11\x44\x45VICE_CAPABILITY\x10\x03\x12\x11\n\rDEVICE_STATUS\x10\x04\x12\x0b\n\x07LOGGING\x10\x05\x12\x0b\n\x07SENSORS\x10\x06\x12\x14\n\x10\x43OMPANION_STATUS\x10\x07\x12\x12\n\x0e\x44\x45VICE_COMMAND\x10\x08\x12\x12\n\x0e\x42ISTO_SETTINGS\x10\t\x12\x0c\n\x08WELLNESS\x10\n\x12\x08\n\x04TEST\x10\x0b\x12\x0f\n\x0b\x42LE_SERVICE\x10\x0c\x12\r\n\tAPOLLO_QA\x10~\x12\r\n\tTRANSLATE\x10\x7f\x42)\n\x1d\x63om.google.android.bisto.nanoB\x08Protocol')
-)
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0f\x61udiowear.proto\x12$apollo.lib.apollo_dev_util_lib.proto*\x8d\x02\n\x0cMessageGroup\x12\x19\n\x15UNKNOWN_MESSAGE_GROUP\x10\x00\x12\x10\n\x0c\x44\x45VICE_INPUT\x10\x01\x12\x07\n\x03OTA\x10\x02\x12\x15\n\x11\x44\x45VICE_CAPABILITY\x10\x03\x12\x11\n\rDEVICE_STATUS\x10\x04\x12\x0b\n\x07LOGGING\x10\x05\x12\x0b\n\x07SENSORS\x10\x06\x12\x14\n\x10\x43OMPANION_STATUS\x10\x07\x12\x12\n\x0e\x44\x45VICE_COMMAND\x10\x08\x12\x12\n\x0e\x42ISTO_SETTINGS\x10\t\x12\x0c\n\x08WELLNESS\x10\n\x12\x08\n\x04TEST\x10\x0b\x12\x0f\n\x0b\x42LE_SERVICE\x10\x0c\x12\r\n\tAPOLLO_QA\x10~\x12\r\n\tTRANSLATE\x10\x7f\x42)\n\x1d\x63om.google.android.bisto.nanoB\x08Protocol')
 
-_MESSAGEGROUP = _descriptor.EnumDescriptor(
-  name='MessageGroup',
-  full_name='apollo.lib.apollo_dev_util_lib.proto.MessageGroup',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='UNKNOWN_MESSAGE_GROUP', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DEVICE_INPUT', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='OTA', index=2, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DEVICE_CAPABILITY', index=3, number=3,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DEVICE_STATUS', index=4, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='LOGGING', index=5, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='SENSORS', index=6, number=6,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='COMPANION_STATUS', index=7, number=7,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='DEVICE_COMMAND', index=8, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='BISTO_SETTINGS', index=9, number=9,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='WELLNESS', index=10, number=10,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TEST', index=11, number=11,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='BLE_SERVICE', index=12, number=12,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='APOLLO_QA', index=13, number=126,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TRANSLATE', index=14, number=127,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=58,
-  serialized_end=327,
-)
-_sym_db.RegisterEnumDescriptor(_MESSAGEGROUP)
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'audiowear_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
 
-MessageGroup = enum_type_wrapper.EnumTypeWrapper(_MESSAGEGROUP)
-UNKNOWN_MESSAGE_GROUP = 0
-DEVICE_INPUT = 1
-OTA = 2
-DEVICE_CAPABILITY = 3
-DEVICE_STATUS = 4
-LOGGING = 5
-SENSORS = 6
-COMPANION_STATUS = 7
-DEVICE_COMMAND = 8
-BISTO_SETTINGS = 9
-WELLNESS = 10
-TEST = 11
-BLE_SERVICE = 12
-APOLLO_QA = 126
-TRANSLATE = 127
-
-
-DESCRIPTOR.enum_types_by_name['MessageGroup'] = _MESSAGEGROUP
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\035com.google.android.bisto.nanoB\010Protocol'))
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n\035com.google.android.bisto.nanoB\010Protocol'
+  _MESSAGEGROUP._serialized_start=58
+  _MESSAGEGROUP._serialized_end=327
 # @@protoc_insertion_point(module_scope)
diff --git a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/google/protobuf/descriptor_pb2.py b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/google/protobuf/descriptor_pb2.py
index e3b4558..dd9775c 100644
--- a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/google/protobuf/descriptor_pb2.py
+++ b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/google/protobuf/descriptor_pb2.py
@@ -1,11 +1,10 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: google/protobuf/descriptor.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
+from google.protobuf import descriptor_pool as _descriptor_pool
 from google.protobuf import symbol_database as _symbol_database
 # @@protoc_insertion_point(imports)
 
@@ -14,1559 +13,1470 @@
 
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='google/protobuf/descriptor.proto',
-  package='google.protobuf',
-  syntax='proto2',
-  serialized_pb=_b('\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xe4\x03\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x1a,\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xa9\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"$\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x8c\x01\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xcc\x04\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12,\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08:\x05\x66\x61lse\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe6\x01\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xa0\x02\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x8d\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"z\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xb1\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x63\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\tB)\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01')
-)
+if _descriptor._USE_C_DESCRIPTORS == False:
+  DESCRIPTOR = _descriptor.FileDescriptor(
+    name='google/protobuf/descriptor.proto',
+    package='google.protobuf',
+    syntax='proto2',
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+    serialized_pb=b'\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xe4\x03\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x1a,\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xa9\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"$\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x8c\x01\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xcc\x04\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12,\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08:\x05\x66\x61lse\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe6\x01\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xa0\x02\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x8d\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"z\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xb1\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x63\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\tB)\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01'
+  )
+else:
+  DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n google/protobuf/descriptor.proto\x12\x0fgoogle.protobuf\"G\n\x11\x46ileDescriptorSet\x12\x32\n\x04\x66ile\x18\x01 \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xdb\x03\n\x13\x46ileDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07package\x18\x02 \x01(\t\x12\x12\n\ndependency\x18\x03 \x03(\t\x12\x19\n\x11public_dependency\x18\n \x03(\x05\x12\x17\n\x0fweak_dependency\x18\x0b \x03(\x05\x12\x36\n\x0cmessage_type\x18\x04 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x05 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12\x38\n\x07service\x18\x06 \x03(\x0b\x32\'.google.protobuf.ServiceDescriptorProto\x12\x38\n\textension\x18\x07 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12-\n\x07options\x18\x08 \x01(\x0b\x32\x1c.google.protobuf.FileOptions\x12\x39\n\x10source_code_info\x18\t \x01(\x0b\x32\x1f.google.protobuf.SourceCodeInfo\x12\x0e\n\x06syntax\x18\x0c \x01(\t\"\xe4\x03\n\x0f\x44\x65scriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x34\n\x05\x66ield\x18\x02 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x38\n\textension\x18\x06 \x03(\x0b\x32%.google.protobuf.FieldDescriptorProto\x12\x35\n\x0bnested_type\x18\x03 \x03(\x0b\x32 .google.protobuf.DescriptorProto\x12\x37\n\tenum_type\x18\x04 \x03(\x0b\x32$.google.protobuf.EnumDescriptorProto\x12H\n\x0f\x65xtension_range\x18\x05 \x03(\x0b\x32/.google.protobuf.DescriptorProto.ExtensionRange\x12\x39\n\noneof_decl\x18\x08 \x03(\x0b\x32%.google.protobuf.OneofDescriptorProto\x12\x30\n\x07options\x18\x07 \x01(\x0b\x32\x1f.google.protobuf.MessageOptions\x1a,\n\x0e\x45xtensionRange\x12\r\n\x05start\x18\x01 \x01(\x05\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x05\"\xa9\x05\n\x14\x46ieldDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x03 \x01(\x05\x12:\n\x05label\x18\x04 \x01(\x0e\x32+.google.protobuf.FieldDescriptorProto.Label\x12\x38\n\x04type\x18\x05 \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x11\n\ttype_name\x18\x06 \x01(\t\x12\x10\n\x08\x65xtendee\x18\x02 \x01(\t\x12\x15\n\rdefault_value\x18\x07 \x01(\t\x12\x13\n\x0boneof_index\x18\t \x01(\x05\x12.\n\x07options\x18\x08 \x01(\x0b\x32\x1d.google.protobuf.FieldOptions\"\xb6\x02\n\x04Type\x12\x0f\n\x0bTYPE_DOUBLE\x10\x01\x12\x0e\n\nTYPE_FLOAT\x10\x02\x12\x0e\n\nTYPE_INT64\x10\x03\x12\x0f\n\x0bTYPE_UINT64\x10\x04\x12\x0e\n\nTYPE_INT32\x10\x05\x12\x10\n\x0cTYPE_FIXED64\x10\x06\x12\x10\n\x0cTYPE_FIXED32\x10\x07\x12\r\n\tTYPE_BOOL\x10\x08\x12\x0f\n\x0bTYPE_STRING\x10\t\x12\x0e\n\nTYPE_GROUP\x10\n\x12\x10\n\x0cTYPE_MESSAGE\x10\x0b\x12\x0e\n\nTYPE_BYTES\x10\x0c\x12\x0f\n\x0bTYPE_UINT32\x10\r\x12\r\n\tTYPE_ENUM\x10\x0e\x12\x11\n\rTYPE_SFIXED32\x10\x0f\x12\x11\n\rTYPE_SFIXED64\x10\x10\x12\x0f\n\x0bTYPE_SINT32\x10\x11\x12\x0f\n\x0bTYPE_SINT64\x10\x12\"C\n\x05Label\x12\x12\n\x0eLABEL_OPTIONAL\x10\x01\x12\x12\n\x0eLABEL_REQUIRED\x10\x02\x12\x12\n\x0eLABEL_REPEATED\x10\x03\"$\n\x14OneofDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x8c\x01\n\x13\x45numDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x03(\x0b\x32).google.protobuf.EnumValueDescriptorProto\x12-\n\x07options\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.EnumOptions\"l\n\x18\x45numValueDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06number\x18\x02 \x01(\x05\x12\x32\n\x07options\x18\x03 \x01(\x0b\x32!.google.protobuf.EnumValueOptions\"\x90\x01\n\x16ServiceDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x36\n\x06method\x18\x02 \x03(\x0b\x32&.google.protobuf.MethodDescriptorProto\x12\x30\n\x07options\x18\x03 \x01(\x0b\x32\x1f.google.protobuf.ServiceOptions\"\xc1\x01\n\x15MethodDescriptorProto\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\ninput_type\x18\x02 \x01(\t\x12\x13\n\x0boutput_type\x18\x03 \x01(\t\x12/\n\x07options\x18\x04 \x01(\x0b\x32\x1e.google.protobuf.MethodOptions\x12\x1f\n\x10\x63lient_streaming\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10server_streaming\x18\x06 \x01(\x08:\x05\x66\x61lse\"\xcc\x04\n\x0b\x46ileOptions\x12\x14\n\x0cjava_package\x18\x01 \x01(\t\x12\x1c\n\x14java_outer_classname\x18\x08 \x01(\t\x12\"\n\x13java_multiple_files\x18\n \x01(\x08:\x05\x66\x61lse\x12,\n\x1djava_generate_equals_and_hash\x18\x14 \x01(\x08:\x05\x66\x61lse\x12%\n\x16java_string_check_utf8\x18\x1b \x01(\x08:\x05\x66\x61lse\x12\x46\n\x0coptimize_for\x18\t \x01(\x0e\x32).google.protobuf.FileOptions.OptimizeMode:\x05SPEED\x12\x12\n\ngo_package\x18\x0b \x01(\t\x12\"\n\x13\x63\x63_generic_services\x18\x10 \x01(\x08:\x05\x66\x61lse\x12$\n\x15java_generic_services\x18\x11 \x01(\x08:\x05\x66\x61lse\x12\"\n\x13py_generic_services\x18\x12 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x1f\n\x10\x63\x63_enable_arenas\x18\x1f \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\":\n\x0cOptimizeMode\x12\t\n\x05SPEED\x10\x01\x12\r\n\tCODE_SIZE\x10\x02\x12\x10\n\x0cLITE_RUNTIME\x10\x03*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xe6\x01\n\x0eMessageOptions\x12&\n\x17message_set_wire_format\x18\x01 \x01(\x08:\x05\x66\x61lse\x12.\n\x1fno_standard_descriptor_accessor\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x11\n\tmap_entry\x18\x07 \x01(\x08\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\xa0\x02\n\x0c\x46ieldOptions\x12:\n\x05\x63type\x18\x01 \x01(\x0e\x32#.google.protobuf.FieldOptions.CType:\x06STRING\x12\x0e\n\x06packed\x18\x02 \x01(\x08\x12\x13\n\x04lazy\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04weak\x18\n \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption\"/\n\x05\x43Type\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x43ORD\x10\x01\x12\x10\n\x0cSTRING_PIECE\x10\x02*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x8d\x01\n\x0b\x45numOptions\x12\x13\n\x0b\x61llow_alias\x18\x02 \x01(\x08\x12\x19\n\ndeprecated\x18\x03 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"}\n\x10\x45numValueOptions\x12\x19\n\ndeprecated\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"{\n\x0eServiceOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"z\n\rMethodOptions\x12\x19\n\ndeprecated\x18! \x01(\x08:\x05\x66\x61lse\x12\x43\n\x14uninterpreted_option\x18\xe7\x07 \x03(\x0b\x32$.google.protobuf.UninterpretedOption*\t\x08\xe8\x07\x10\x80\x80\x80\x80\x02\"\x9e\x02\n\x13UninterpretedOption\x12;\n\x04name\x18\x02 \x03(\x0b\x32-.google.protobuf.UninterpretedOption.NamePart\x12\x18\n\x10identifier_value\x18\x03 \x01(\t\x12\x1a\n\x12positive_int_value\x18\x04 \x01(\x04\x12\x1a\n\x12negative_int_value\x18\x05 \x01(\x03\x12\x14\n\x0c\x64ouble_value\x18\x06 \x01(\x01\x12\x14\n\x0cstring_value\x18\x07 \x01(\x0c\x12\x17\n\x0f\x61ggregate_value\x18\x08 \x01(\t\x1a\x33\n\x08NamePart\x12\x11\n\tname_part\x18\x01 \x02(\t\x12\x14\n\x0cis_extension\x18\x02 \x02(\x08\"\xb1\x01\n\x0eSourceCodeInfo\x12:\n\x08location\x18\x01 \x03(\x0b\x32(.google.protobuf.SourceCodeInfo.Location\x1a\x63\n\x08Location\x12\x10\n\x04path\x18\x01 \x03(\x05\x42\x02\x10\x01\x12\x10\n\x04span\x18\x02 \x03(\x05\x42\x02\x10\x01\x12\x18\n\x10leading_comments\x18\x03 \x01(\t\x12\x19\n\x11trailing_comments\x18\x04 \x01(\tB)\n\x13\x63om.google.protobufB\x10\x44\x65scriptorProtosH\x01')
 
+if _descriptor._USE_C_DESCRIPTORS == False:
+  _FIELDDESCRIPTORPROTO_TYPE = _descriptor.EnumDescriptor(
+    name='Type',
+    full_name='google.protobuf.FieldDescriptorProto.Type',
+    filename=None,
+    file=DESCRIPTOR,
+    create_key=_descriptor._internal_create_key,
+    values=[
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_DOUBLE', index=0, number=1,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_FLOAT', index=1, number=2,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_INT64', index=2, number=3,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_UINT64', index=3, number=4,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_INT32', index=4, number=5,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_FIXED64', index=5, number=6,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_FIXED32', index=6, number=7,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_BOOL', index=7, number=8,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_STRING', index=8, number=9,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_GROUP', index=9, number=10,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_MESSAGE', index=10, number=11,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_BYTES', index=11, number=12,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_UINT32', index=12, number=13,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_ENUM', index=13, number=14,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_SFIXED32', index=14, number=15,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_SFIXED64', index=15, number=16,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_SINT32', index=16, number=17,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='TYPE_SINT64', index=17, number=18,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+    ],
+    containing_type=None,
+    serialized_options=None,
+  )
+  _sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_TYPE)
 
+  _FIELDDESCRIPTORPROTO_LABEL = _descriptor.EnumDescriptor(
+    name='Label',
+    full_name='google.protobuf.FieldDescriptorProto.Label',
+    filename=None,
+    file=DESCRIPTOR,
+    create_key=_descriptor._internal_create_key,
+    values=[
+      _descriptor.EnumValueDescriptor(
+        name='LABEL_OPTIONAL', index=0, number=1,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='LABEL_REQUIRED', index=1, number=2,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='LABEL_REPEATED', index=2, number=3,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+    ],
+    containing_type=None,
+    serialized_options=None,
+  )
+  _sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_LABEL)
 
-_FIELDDESCRIPTORPROTO_TYPE = _descriptor.EnumDescriptor(
-  name='Type',
-  full_name='google.protobuf.FieldDescriptorProto.Type',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_DOUBLE', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_FLOAT', index=1, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_INT64', index=2, number=3,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_UINT64', index=3, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_INT32', index=4, number=5,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_FIXED64', index=5, number=6,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_FIXED32', index=6, number=7,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_BOOL', index=7, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_STRING', index=8, number=9,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_GROUP', index=9, number=10,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_MESSAGE', index=10, number=11,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_BYTES', index=11, number=12,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_UINT32', index=12, number=13,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_ENUM', index=13, number=14,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_SFIXED32', index=14, number=15,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_SFIXED64', index=15, number=16,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_SINT32', index=16, number=17,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='TYPE_SINT64', index=17, number=18,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1394,
-  serialized_end=1704,
-)
-_sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_TYPE)
+  _FILEOPTIONS_OPTIMIZEMODE = _descriptor.EnumDescriptor(
+    name='OptimizeMode',
+    full_name='google.protobuf.FileOptions.OptimizeMode',
+    filename=None,
+    file=DESCRIPTOR,
+    create_key=_descriptor._internal_create_key,
+    values=[
+      _descriptor.EnumValueDescriptor(
+        name='SPEED', index=0, number=1,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='CODE_SIZE', index=1, number=2,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='LITE_RUNTIME', index=2, number=3,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+    ],
+    containing_type=None,
+    serialized_options=None,
+  )
+  _sym_db.RegisterEnumDescriptor(_FILEOPTIONS_OPTIMIZEMODE)
 
-_FIELDDESCRIPTORPROTO_LABEL = _descriptor.EnumDescriptor(
-  name='Label',
-  full_name='google.protobuf.FieldDescriptorProto.Label',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='LABEL_OPTIONAL', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='LABEL_REQUIRED', index=1, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='LABEL_REPEATED', index=2, number=3,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=1706,
-  serialized_end=1773,
-)
-_sym_db.RegisterEnumDescriptor(_FIELDDESCRIPTORPROTO_LABEL)
+  _FIELDOPTIONS_CTYPE = _descriptor.EnumDescriptor(
+    name='CType',
+    full_name='google.protobuf.FieldOptions.CType',
+    filename=None,
+    file=DESCRIPTOR,
+    create_key=_descriptor._internal_create_key,
+    values=[
+      _descriptor.EnumValueDescriptor(
+        name='STRING', index=0, number=0,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='CORD', index=1, number=1,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+      _descriptor.EnumValueDescriptor(
+        name='STRING_PIECE', index=2, number=2,
+        serialized_options=None,
+        type=None,
+        create_key=_descriptor._internal_create_key),
+    ],
+    containing_type=None,
+    serialized_options=None,
+  )
+  _sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_CTYPE)
 
-_FILEOPTIONS_OPTIMIZEMODE = _descriptor.EnumDescriptor(
-  name='OptimizeMode',
-  full_name='google.protobuf.FileOptions.OptimizeMode',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='SPEED', index=0, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CODE_SIZE', index=1, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='LITE_RUNTIME', index=2, number=3,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=2929,
-  serialized_end=2987,
-)
-_sym_db.RegisterEnumDescriptor(_FILEOPTIONS_OPTIMIZEMODE)
 
-_FIELDOPTIONS_CTYPE = _descriptor.EnumDescriptor(
-  name='CType',
-  full_name='google.protobuf.FieldOptions.CType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='STRING', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='CORD', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='STRING_PIECE', index=2, number=2,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=3464,
-  serialized_end=3511,
-)
-_sym_db.RegisterEnumDescriptor(_FIELDOPTIONS_CTYPE)
+  _FILEDESCRIPTORSET = _descriptor.Descriptor(
+    name='FileDescriptorSet',
+    full_name='google.protobuf.FileDescriptorSet',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='file', full_name='google.protobuf.FileDescriptorSet.file', index=0,
+        number=1, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_FILEDESCRIPTORSET = _descriptor.Descriptor(
-  name='FileDescriptorSet',
-  full_name='google.protobuf.FileDescriptorSet',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='file', full_name='google.protobuf.FileDescriptorSet.file', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=53,
-  serialized_end=124,
-)
+  _FILEDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='FileDescriptorProto',
+    full_name='google.protobuf.FileDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.FileDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='package', full_name='google.protobuf.FileDescriptorProto.package', index=1,
+        number=2, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='dependency', full_name='google.protobuf.FileDescriptorProto.dependency', index=2,
+        number=3, type=9, cpp_type=9, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='public_dependency', full_name='google.protobuf.FileDescriptorProto.public_dependency', index=3,
+        number=10, type=5, cpp_type=1, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='weak_dependency', full_name='google.protobuf.FileDescriptorProto.weak_dependency', index=4,
+        number=11, type=5, cpp_type=1, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='message_type', full_name='google.protobuf.FileDescriptorProto.message_type', index=5,
+        number=4, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='enum_type', full_name='google.protobuf.FileDescriptorProto.enum_type', index=6,
+        number=5, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='service', full_name='google.protobuf.FileDescriptorProto.service', index=7,
+        number=6, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='extension', full_name='google.protobuf.FileDescriptorProto.extension', index=8,
+        number=7, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.FileDescriptorProto.options', index=9,
+        number=8, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='source_code_info', full_name='google.protobuf.FileDescriptorProto.source_code_info', index=10,
+        number=9, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='syntax', full_name='google.protobuf.FileDescriptorProto.syntax', index=11,
+        number=12, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_FILEDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='FileDescriptorProto',
-  full_name='google.protobuf.FileDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.FileDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='package', full_name='google.protobuf.FileDescriptorProto.package', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='dependency', full_name='google.protobuf.FileDescriptorProto.dependency', index=2,
-      number=3, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='public_dependency', full_name='google.protobuf.FileDescriptorProto.public_dependency', index=3,
-      number=10, type=5, cpp_type=1, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='weak_dependency', full_name='google.protobuf.FileDescriptorProto.weak_dependency', index=4,
-      number=11, type=5, cpp_type=1, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='message_type', full_name='google.protobuf.FileDescriptorProto.message_type', index=5,
-      number=4, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='enum_type', full_name='google.protobuf.FileDescriptorProto.enum_type', index=6,
-      number=5, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='service', full_name='google.protobuf.FileDescriptorProto.service', index=7,
-      number=6, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='extension', full_name='google.protobuf.FileDescriptorProto.extension', index=8,
-      number=7, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.FileDescriptorProto.options', index=9,
-      number=8, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='source_code_info', full_name='google.protobuf.FileDescriptorProto.source_code_info', index=10,
-      number=9, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='syntax', full_name='google.protobuf.FileDescriptorProto.syntax', index=11,
-      number=12, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=127,
-  serialized_end=602,
-)
+  _DESCRIPTORPROTO_EXTENSIONRANGE = _descriptor.Descriptor(
+    name='ExtensionRange',
+    full_name='google.protobuf.DescriptorProto.ExtensionRange',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='start', full_name='google.protobuf.DescriptorProto.ExtensionRange.start', index=0,
+        number=1, type=5, cpp_type=1, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='end', full_name='google.protobuf.DescriptorProto.ExtensionRange.end', index=1,
+        number=2, type=5, cpp_type=1, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
+  _DESCRIPTORPROTO = _descriptor.Descriptor(
+    name='DescriptorProto',
+    full_name='google.protobuf.DescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.DescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='field', full_name='google.protobuf.DescriptorProto.field', index=1,
+        number=2, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='extension', full_name='google.protobuf.DescriptorProto.extension', index=2,
+        number=6, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='nested_type', full_name='google.protobuf.DescriptorProto.nested_type', index=3,
+        number=3, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='enum_type', full_name='google.protobuf.DescriptorProto.enum_type', index=4,
+        number=4, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='extension_range', full_name='google.protobuf.DescriptorProto.extension_range', index=5,
+        number=5, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='oneof_decl', full_name='google.protobuf.DescriptorProto.oneof_decl', index=6,
+        number=8, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.DescriptorProto.options', index=7,
+        number=7, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[_DESCRIPTORPROTO_EXTENSIONRANGE, ],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
-_DESCRIPTORPROTO_EXTENSIONRANGE = _descriptor.Descriptor(
-  name='ExtensionRange',
-  full_name='google.protobuf.DescriptorProto.ExtensionRange',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='start', full_name='google.protobuf.DescriptorProto.ExtensionRange.start', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='end', full_name='google.protobuf.DescriptorProto.ExtensionRange.end', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1045,
-  serialized_end=1089,
-)
 
-_DESCRIPTORPROTO = _descriptor.Descriptor(
-  name='DescriptorProto',
-  full_name='google.protobuf.DescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.DescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='field', full_name='google.protobuf.DescriptorProto.field', index=1,
-      number=2, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='extension', full_name='google.protobuf.DescriptorProto.extension', index=2,
-      number=6, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='nested_type', full_name='google.protobuf.DescriptorProto.nested_type', index=3,
-      number=3, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='enum_type', full_name='google.protobuf.DescriptorProto.enum_type', index=4,
-      number=4, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='extension_range', full_name='google.protobuf.DescriptorProto.extension_range', index=5,
-      number=5, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='oneof_decl', full_name='google.protobuf.DescriptorProto.oneof_decl', index=6,
-      number=8, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.DescriptorProto.options', index=7,
-      number=7, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[_DESCRIPTORPROTO_EXTENSIONRANGE, ],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=605,
-  serialized_end=1089,
-)
+  _FIELDDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='FieldDescriptorProto',
+    full_name='google.protobuf.FieldDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.FieldDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='number', full_name='google.protobuf.FieldDescriptorProto.number', index=1,
+        number=3, type=5, cpp_type=1, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='label', full_name='google.protobuf.FieldDescriptorProto.label', index=2,
+        number=4, type=14, cpp_type=8, label=1,
+        has_default_value=False, default_value=1,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='type', full_name='google.protobuf.FieldDescriptorProto.type', index=3,
+        number=5, type=14, cpp_type=8, label=1,
+        has_default_value=False, default_value=1,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='type_name', full_name='google.protobuf.FieldDescriptorProto.type_name', index=4,
+        number=6, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='extendee', full_name='google.protobuf.FieldDescriptorProto.extendee', index=5,
+        number=2, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='default_value', full_name='google.protobuf.FieldDescriptorProto.default_value', index=6,
+        number=7, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='oneof_index', full_name='google.protobuf.FieldDescriptorProto.oneof_index', index=7,
+        number=9, type=5, cpp_type=1, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.FieldDescriptorProto.options', index=8,
+        number=8, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+      _FIELDDESCRIPTORPROTO_TYPE,
+      _FIELDDESCRIPTORPROTO_LABEL,
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_FIELDDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='FieldDescriptorProto',
-  full_name='google.protobuf.FieldDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.FieldDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='number', full_name='google.protobuf.FieldDescriptorProto.number', index=1,
-      number=3, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='label', full_name='google.protobuf.FieldDescriptorProto.label', index=2,
-      number=4, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='type', full_name='google.protobuf.FieldDescriptorProto.type', index=3,
-      number=5, type=14, cpp_type=8, label=1,
-      has_default_value=False, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='type_name', full_name='google.protobuf.FieldDescriptorProto.type_name', index=4,
-      number=6, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='extendee', full_name='google.protobuf.FieldDescriptorProto.extendee', index=5,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='default_value', full_name='google.protobuf.FieldDescriptorProto.default_value', index=6,
-      number=7, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='oneof_index', full_name='google.protobuf.FieldDescriptorProto.oneof_index', index=7,
-      number=9, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.FieldDescriptorProto.options', index=8,
-      number=8, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-    _FIELDDESCRIPTORPROTO_TYPE,
-    _FIELDDESCRIPTORPROTO_LABEL,
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1092,
-  serialized_end=1773,
-)
+  _ONEOFDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='OneofDescriptorProto',
+    full_name='google.protobuf.OneofDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.OneofDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_ONEOFDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='OneofDescriptorProto',
-  full_name='google.protobuf.OneofDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.OneofDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1775,
-  serialized_end=1811,
-)
+  _ENUMDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='EnumDescriptorProto',
+    full_name='google.protobuf.EnumDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.EnumDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='value', full_name='google.protobuf.EnumDescriptorProto.value', index=1,
+        number=2, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.EnumDescriptorProto.options', index=2,
+        number=3, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_ENUMDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='EnumDescriptorProto',
-  full_name='google.protobuf.EnumDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.EnumDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='value', full_name='google.protobuf.EnumDescriptorProto.value', index=1,
-      number=2, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.EnumDescriptorProto.options', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1814,
-  serialized_end=1954,
-)
+  _ENUMVALUEDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='EnumValueDescriptorProto',
+    full_name='google.protobuf.EnumValueDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.EnumValueDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='number', full_name='google.protobuf.EnumValueDescriptorProto.number', index=1,
+        number=2, type=5, cpp_type=1, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.EnumValueDescriptorProto.options', index=2,
+        number=3, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_ENUMVALUEDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='EnumValueDescriptorProto',
-  full_name='google.protobuf.EnumValueDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.EnumValueDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='number', full_name='google.protobuf.EnumValueDescriptorProto.number', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.EnumValueDescriptorProto.options', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1956,
-  serialized_end=2064,
-)
+  _SERVICEDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='ServiceDescriptorProto',
+    full_name='google.protobuf.ServiceDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.ServiceDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='method', full_name='google.protobuf.ServiceDescriptorProto.method', index=1,
+        number=2, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.ServiceDescriptorProto.options', index=2,
+        number=3, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_SERVICEDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='ServiceDescriptorProto',
-  full_name='google.protobuf.ServiceDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.ServiceDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='method', full_name='google.protobuf.ServiceDescriptorProto.method', index=1,
-      number=2, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.ServiceDescriptorProto.options', index=2,
-      number=3, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2067,
-  serialized_end=2211,
-)
+  _METHODDESCRIPTORPROTO = _descriptor.Descriptor(
+    name='MethodDescriptorProto',
+    full_name='google.protobuf.MethodDescriptorProto',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.MethodDescriptorProto.name', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='input_type', full_name='google.protobuf.MethodDescriptorProto.input_type', index=1,
+        number=2, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='output_type', full_name='google.protobuf.MethodDescriptorProto.output_type', index=2,
+        number=3, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='options', full_name='google.protobuf.MethodDescriptorProto.options', index=3,
+        number=4, type=11, cpp_type=10, label=1,
+        has_default_value=False, default_value=None,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='client_streaming', full_name='google.protobuf.MethodDescriptorProto.client_streaming', index=4,
+        number=5, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='server_streaming', full_name='google.protobuf.MethodDescriptorProto.server_streaming', index=5,
+        number=6, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
 
-_METHODDESCRIPTORPROTO = _descriptor.Descriptor(
-  name='MethodDescriptorProto',
-  full_name='google.protobuf.MethodDescriptorProto',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.MethodDescriptorProto.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='input_type', full_name='google.protobuf.MethodDescriptorProto.input_type', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='output_type', full_name='google.protobuf.MethodDescriptorProto.output_type', index=2,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='options', full_name='google.protobuf.MethodDescriptorProto.options', index=3,
-      number=4, type=11, cpp_type=10, label=1,
-      has_default_value=False, default_value=None,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='client_streaming', full_name='google.protobuf.MethodDescriptorProto.client_streaming', index=4,
-      number=5, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='server_streaming', full_name='google.protobuf.MethodDescriptorProto.server_streaming', index=5,
-      number=6, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=2214,
-  serialized_end=2407,
-)
-
-
-_FILEOPTIONS = _descriptor.Descriptor(
-  name='FileOptions',
-  full_name='google.protobuf.FileOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='java_package', full_name='google.protobuf.FileOptions.java_package', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='java_outer_classname', full_name='google.protobuf.FileOptions.java_outer_classname', index=1,
-      number=8, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='java_multiple_files', full_name='google.protobuf.FileOptions.java_multiple_files', index=2,
-      number=10, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='java_generate_equals_and_hash', full_name='google.protobuf.FileOptions.java_generate_equals_and_hash', index=3,
-      number=20, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='java_string_check_utf8', full_name='google.protobuf.FileOptions.java_string_check_utf8', index=4,
-      number=27, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='optimize_for', full_name='google.protobuf.FileOptions.optimize_for', index=5,
-      number=9, type=14, cpp_type=8, label=1,
-      has_default_value=True, default_value=1,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='go_package', full_name='google.protobuf.FileOptions.go_package', index=6,
-      number=11, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='cc_generic_services', full_name='google.protobuf.FileOptions.cc_generic_services', index=7,
-      number=16, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='java_generic_services', full_name='google.protobuf.FileOptions.java_generic_services', index=8,
-      number=17, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='py_generic_services', full_name='google.protobuf.FileOptions.py_generic_services', index=9,
-      number=18, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.FileOptions.deprecated', index=10,
-      number=23, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='cc_enable_arenas', full_name='google.protobuf.FileOptions.cc_enable_arenas', index=11,
-      number=31, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.FileOptions.uninterpreted_option', index=12,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-    _FILEOPTIONS_OPTIMIZEMODE,
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=2410,
-  serialized_end=2998,
-)
-
-
-_MESSAGEOPTIONS = _descriptor.Descriptor(
-  name='MessageOptions',
-  full_name='google.protobuf.MessageOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='message_set_wire_format', full_name='google.protobuf.MessageOptions.message_set_wire_format', index=0,
-      number=1, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='no_standard_descriptor_accessor', full_name='google.protobuf.MessageOptions.no_standard_descriptor_accessor', index=1,
-      number=2, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.MessageOptions.deprecated', index=2,
-      number=3, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='map_entry', full_name='google.protobuf.MessageOptions.map_entry', index=3,
-      number=7, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.MessageOptions.uninterpreted_option', index=4,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3001,
-  serialized_end=3231,
-)
-
-
-_FIELDOPTIONS = _descriptor.Descriptor(
-  name='FieldOptions',
-  full_name='google.protobuf.FieldOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='ctype', full_name='google.protobuf.FieldOptions.ctype', index=0,
-      number=1, type=14, cpp_type=8, label=1,
-      has_default_value=True, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='packed', full_name='google.protobuf.FieldOptions.packed', index=1,
-      number=2, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='lazy', full_name='google.protobuf.FieldOptions.lazy', index=2,
-      number=5, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.FieldOptions.deprecated', index=3,
-      number=3, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='weak', full_name='google.protobuf.FieldOptions.weak', index=4,
-      number=10, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.FieldOptions.uninterpreted_option', index=5,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-    _FIELDOPTIONS_CTYPE,
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3234,
-  serialized_end=3522,
-)
-
-
-_ENUMOPTIONS = _descriptor.Descriptor(
-  name='EnumOptions',
-  full_name='google.protobuf.EnumOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='allow_alias', full_name='google.protobuf.EnumOptions.allow_alias', index=0,
-      number=2, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.EnumOptions.deprecated', index=1,
-      number=3, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.EnumOptions.uninterpreted_option', index=2,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3525,
-  serialized_end=3666,
-)
-
-
-_ENUMVALUEOPTIONS = _descriptor.Descriptor(
-  name='EnumValueOptions',
-  full_name='google.protobuf.EnumValueOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.EnumValueOptions.deprecated', index=0,
-      number=1, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.EnumValueOptions.uninterpreted_option', index=1,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3668,
-  serialized_end=3793,
-)
-
-
-_SERVICEOPTIONS = _descriptor.Descriptor(
-  name='ServiceOptions',
-  full_name='google.protobuf.ServiceOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.ServiceOptions.deprecated', index=0,
-      number=33, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.ServiceOptions.uninterpreted_option', index=1,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3795,
-  serialized_end=3918,
-)
-
-
-_METHODOPTIONS = _descriptor.Descriptor(
-  name='MethodOptions',
-  full_name='google.protobuf.MethodOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='deprecated', full_name='google.protobuf.MethodOptions.deprecated', index=0,
-      number=33, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='uninterpreted_option', full_name='google.protobuf.MethodOptions.uninterpreted_option', index=1,
-      number=999, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=True,
-  syntax='proto2',
-  extension_ranges=[(1000, 536870912), ],
-  oneofs=[
-  ],
-  serialized_start=3920,
-  serialized_end=4042,
-)
-
-
-_UNINTERPRETEDOPTION_NAMEPART = _descriptor.Descriptor(
-  name='NamePart',
-  full_name='google.protobuf.UninterpretedOption.NamePart',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name_part', full_name='google.protobuf.UninterpretedOption.NamePart.name_part', index=0,
-      number=1, type=9, cpp_type=9, label=2,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='is_extension', full_name='google.protobuf.UninterpretedOption.NamePart.is_extension', index=1,
-      number=2, type=8, cpp_type=7, label=2,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=4280,
-  serialized_end=4331,
-)
-
-_UNINTERPRETEDOPTION = _descriptor.Descriptor(
-  name='UninterpretedOption',
-  full_name='google.protobuf.UninterpretedOption',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.UninterpretedOption.name', index=0,
-      number=2, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='identifier_value', full_name='google.protobuf.UninterpretedOption.identifier_value', index=1,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='positive_int_value', full_name='google.protobuf.UninterpretedOption.positive_int_value', index=2,
-      number=4, type=4, cpp_type=4, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='negative_int_value', full_name='google.protobuf.UninterpretedOption.negative_int_value', index=3,
-      number=5, type=3, cpp_type=2, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='double_value', full_name='google.protobuf.UninterpretedOption.double_value', index=4,
-      number=6, type=1, cpp_type=5, label=1,
-      has_default_value=False, default_value=float(0),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='string_value', full_name='google.protobuf.UninterpretedOption.string_value', index=5,
-      number=7, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='aggregate_value', full_name='google.protobuf.UninterpretedOption.aggregate_value', index=6,
-      number=8, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[_UNINTERPRETEDOPTION_NAMEPART, ],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=4045,
-  serialized_end=4331,
-)
-
-
-_SOURCECODEINFO_LOCATION = _descriptor.Descriptor(
-  name='Location',
-  full_name='google.protobuf.SourceCodeInfo.Location',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='path', full_name='google.protobuf.SourceCodeInfo.Location.path', index=0,
-      number=1, type=5, cpp_type=1, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='span', full_name='google.protobuf.SourceCodeInfo.Location.span', index=1,
-      number=2, type=5, cpp_type=1, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='leading_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_comments', index=2,
-      number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='trailing_comments', full_name='google.protobuf.SourceCodeInfo.Location.trailing_comments', index=3,
-      number=4, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=4412,
-  serialized_end=4511,
-)
-
-_SOURCECODEINFO = _descriptor.Descriptor(
-  name='SourceCodeInfo',
-  full_name='google.protobuf.SourceCodeInfo',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='location', full_name='google.protobuf.SourceCodeInfo.location', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[_SOURCECODEINFO_LOCATION, ],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=4334,
-  serialized_end=4511,
-)
-
-_FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO
-_FILEDESCRIPTORPROTO.fields_by_name['message_type'].message_type = _DESCRIPTORPROTO
-_FILEDESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
-_FILEDESCRIPTORPROTO.fields_by_name['service'].message_type = _SERVICEDESCRIPTORPROTO
-_FILEDESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
-_FILEDESCRIPTORPROTO.fields_by_name['options'].message_type = _FILEOPTIONS
-_FILEDESCRIPTORPROTO.fields_by_name['source_code_info'].message_type = _SOURCECODEINFO
-_DESCRIPTORPROTO_EXTENSIONRANGE.containing_type = _DESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['field'].message_type = _FIELDDESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['nested_type'].message_type = _DESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['extension_range'].message_type = _DESCRIPTORPROTO_EXTENSIONRANGE
-_DESCRIPTORPROTO.fields_by_name['oneof_decl'].message_type = _ONEOFDESCRIPTORPROTO
-_DESCRIPTORPROTO.fields_by_name['options'].message_type = _MESSAGEOPTIONS
-_FIELDDESCRIPTORPROTO.fields_by_name['label'].enum_type = _FIELDDESCRIPTORPROTO_LABEL
-_FIELDDESCRIPTORPROTO.fields_by_name['type'].enum_type = _FIELDDESCRIPTORPROTO_TYPE
-_FIELDDESCRIPTORPROTO.fields_by_name['options'].message_type = _FIELDOPTIONS
-_FIELDDESCRIPTORPROTO_TYPE.containing_type = _FIELDDESCRIPTORPROTO
-_FIELDDESCRIPTORPROTO_LABEL.containing_type = _FIELDDESCRIPTORPROTO
-_ENUMDESCRIPTORPROTO.fields_by_name['value'].message_type = _ENUMVALUEDESCRIPTORPROTO
-_ENUMDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMOPTIONS
-_ENUMVALUEDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMVALUEOPTIONS
-_SERVICEDESCRIPTORPROTO.fields_by_name['method'].message_type = _METHODDESCRIPTORPROTO
-_SERVICEDESCRIPTORPROTO.fields_by_name['options'].message_type = _SERVICEOPTIONS
-_METHODDESCRIPTORPROTO.fields_by_name['options'].message_type = _METHODOPTIONS
-_FILEOPTIONS.fields_by_name['optimize_for'].enum_type = _FILEOPTIONS_OPTIMIZEMODE
-_FILEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_FILEOPTIONS_OPTIMIZEMODE.containing_type = _FILEOPTIONS
-_MESSAGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_FIELDOPTIONS.fields_by_name['ctype'].enum_type = _FIELDOPTIONS_CTYPE
-_FIELDOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_FIELDOPTIONS_CTYPE.containing_type = _FIELDOPTIONS
-_ENUMOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_ENUMVALUEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_SERVICEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_METHODOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
-_UNINTERPRETEDOPTION_NAMEPART.containing_type = _UNINTERPRETEDOPTION
-_UNINTERPRETEDOPTION.fields_by_name['name'].message_type = _UNINTERPRETEDOPTION_NAMEPART
-_SOURCECODEINFO_LOCATION.containing_type = _SOURCECODEINFO
-_SOURCECODEINFO.fields_by_name['location'].message_type = _SOURCECODEINFO_LOCATION
-DESCRIPTOR.message_types_by_name['FileDescriptorSet'] = _FILEDESCRIPTORSET
-DESCRIPTOR.message_types_by_name['FileDescriptorProto'] = _FILEDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['DescriptorProto'] = _DESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['FieldDescriptorProto'] = _FIELDDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['OneofDescriptorProto'] = _ONEOFDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['EnumDescriptorProto'] = _ENUMDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['EnumValueDescriptorProto'] = _ENUMVALUEDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['ServiceDescriptorProto'] = _SERVICEDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['MethodDescriptorProto'] = _METHODDESCRIPTORPROTO
-DESCRIPTOR.message_types_by_name['FileOptions'] = _FILEOPTIONS
-DESCRIPTOR.message_types_by_name['MessageOptions'] = _MESSAGEOPTIONS
-DESCRIPTOR.message_types_by_name['FieldOptions'] = _FIELDOPTIONS
-DESCRIPTOR.message_types_by_name['EnumOptions'] = _ENUMOPTIONS
-DESCRIPTOR.message_types_by_name['EnumValueOptions'] = _ENUMVALUEOPTIONS
-DESCRIPTOR.message_types_by_name['ServiceOptions'] = _SERVICEOPTIONS
-DESCRIPTOR.message_types_by_name['MethodOptions'] = _METHODOPTIONS
-DESCRIPTOR.message_types_by_name['UninterpretedOption'] = _UNINTERPRETEDOPTION
-DESCRIPTOR.message_types_by_name['SourceCodeInfo'] = _SOURCECODEINFO
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-FileDescriptorSet = _reflection.GeneratedProtocolMessageType('FileDescriptorSet', (_message.Message,), dict(
-  DESCRIPTOR = _FILEDESCRIPTORSET,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet)
-  ))
-_sym_db.RegisterMessage(FileDescriptorSet)
-
-FileDescriptorProto = _reflection.GeneratedProtocolMessageType('FileDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _FILEDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto)
-  ))
-_sym_db.RegisterMessage(FileDescriptorProto)
+  _FILEOPTIONS = _descriptor.Descriptor(
+    name='FileOptions',
+    full_name='google.protobuf.FileOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='java_package', full_name='google.protobuf.FileOptions.java_package', index=0,
+        number=1, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='java_outer_classname', full_name='google.protobuf.FileOptions.java_outer_classname', index=1,
+        number=8, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='java_multiple_files', full_name='google.protobuf.FileOptions.java_multiple_files', index=2,
+        number=10, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='java_generate_equals_and_hash', full_name='google.protobuf.FileOptions.java_generate_equals_and_hash', index=3,
+        number=20, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='java_string_check_utf8', full_name='google.protobuf.FileOptions.java_string_check_utf8', index=4,
+        number=27, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='optimize_for', full_name='google.protobuf.FileOptions.optimize_for', index=5,
+        number=9, type=14, cpp_type=8, label=1,
+        has_default_value=True, default_value=1,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='go_package', full_name='google.protobuf.FileOptions.go_package', index=6,
+        number=11, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='cc_generic_services', full_name='google.protobuf.FileOptions.cc_generic_services', index=7,
+        number=16, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='java_generic_services', full_name='google.protobuf.FileOptions.java_generic_services', index=8,
+        number=17, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='py_generic_services', full_name='google.protobuf.FileOptions.py_generic_services', index=9,
+        number=18, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.FileOptions.deprecated', index=10,
+        number=23, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='cc_enable_arenas', full_name='google.protobuf.FileOptions.cc_enable_arenas', index=11,
+        number=31, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.FileOptions.uninterpreted_option', index=12,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+      _FILEOPTIONS_OPTIMIZEMODE,
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-DescriptorProto = _reflection.GeneratedProtocolMessageType('DescriptorProto', (_message.Message,), dict(
 
-  ExtensionRange = _reflection.GeneratedProtocolMessageType('ExtensionRange', (_message.Message,), dict(
-    DESCRIPTOR = _DESCRIPTORPROTO_EXTENSIONRANGE,
-    __module__ = 'google.protobuf.descriptor_pb2'
-    # @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange)
-    ))
-  ,
-  DESCRIPTOR = _DESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
-  ))
-_sym_db.RegisterMessage(DescriptorProto)
-_sym_db.RegisterMessage(DescriptorProto.ExtensionRange)
+  _MESSAGEOPTIONS = _descriptor.Descriptor(
+    name='MessageOptions',
+    full_name='google.protobuf.MessageOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='message_set_wire_format', full_name='google.protobuf.MessageOptions.message_set_wire_format', index=0,
+        number=1, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='no_standard_descriptor_accessor', full_name='google.protobuf.MessageOptions.no_standard_descriptor_accessor', index=1,
+        number=2, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.MessageOptions.deprecated', index=2,
+        number=3, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='map_entry', full_name='google.protobuf.MessageOptions.map_entry', index=3,
+        number=7, type=8, cpp_type=7, label=1,
+        has_default_value=False, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.MessageOptions.uninterpreted_option', index=4,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-FieldDescriptorProto = _reflection.GeneratedProtocolMessageType('FieldDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _FIELDDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto)
-  ))
-_sym_db.RegisterMessage(FieldDescriptorProto)
 
-OneofDescriptorProto = _reflection.GeneratedProtocolMessageType('OneofDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _ONEOFDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
-  ))
-_sym_db.RegisterMessage(OneofDescriptorProto)
+  _FIELDOPTIONS = _descriptor.Descriptor(
+    name='FieldOptions',
+    full_name='google.protobuf.FieldOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='ctype', full_name='google.protobuf.FieldOptions.ctype', index=0,
+        number=1, type=14, cpp_type=8, label=1,
+        has_default_value=True, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='packed', full_name='google.protobuf.FieldOptions.packed', index=1,
+        number=2, type=8, cpp_type=7, label=1,
+        has_default_value=False, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='lazy', full_name='google.protobuf.FieldOptions.lazy', index=2,
+        number=5, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.FieldOptions.deprecated', index=3,
+        number=3, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='weak', full_name='google.protobuf.FieldOptions.weak', index=4,
+        number=10, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.FieldOptions.uninterpreted_option', index=5,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+      _FIELDOPTIONS_CTYPE,
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-EnumDescriptorProto = _reflection.GeneratedProtocolMessageType('EnumDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _ENUMDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto)
-  ))
-_sym_db.RegisterMessage(EnumDescriptorProto)
 
-EnumValueDescriptorProto = _reflection.GeneratedProtocolMessageType('EnumValueDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _ENUMVALUEDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto)
-  ))
-_sym_db.RegisterMessage(EnumValueDescriptorProto)
+  _ENUMOPTIONS = _descriptor.Descriptor(
+    name='EnumOptions',
+    full_name='google.protobuf.EnumOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='allow_alias', full_name='google.protobuf.EnumOptions.allow_alias', index=0,
+        number=2, type=8, cpp_type=7, label=1,
+        has_default_value=False, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.EnumOptions.deprecated', index=1,
+        number=3, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.EnumOptions.uninterpreted_option', index=2,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-ServiceDescriptorProto = _reflection.GeneratedProtocolMessageType('ServiceDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _SERVICEDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto)
-  ))
-_sym_db.RegisterMessage(ServiceDescriptorProto)
 
-MethodDescriptorProto = _reflection.GeneratedProtocolMessageType('MethodDescriptorProto', (_message.Message,), dict(
-  DESCRIPTOR = _METHODDESCRIPTORPROTO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto)
-  ))
-_sym_db.RegisterMessage(MethodDescriptorProto)
+  _ENUMVALUEOPTIONS = _descriptor.Descriptor(
+    name='EnumValueOptions',
+    full_name='google.protobuf.EnumValueOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.EnumValueOptions.deprecated', index=0,
+        number=1, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.EnumValueOptions.uninterpreted_option', index=1,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-FileOptions = _reflection.GeneratedProtocolMessageType('FileOptions', (_message.Message,), dict(
-  DESCRIPTOR = _FILEOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.FileOptions)
-  ))
-_sym_db.RegisterMessage(FileOptions)
 
-MessageOptions = _reflection.GeneratedProtocolMessageType('MessageOptions', (_message.Message,), dict(
-  DESCRIPTOR = _MESSAGEOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions)
-  ))
-_sym_db.RegisterMessage(MessageOptions)
+  _SERVICEOPTIONS = _descriptor.Descriptor(
+    name='ServiceOptions',
+    full_name='google.protobuf.ServiceOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.ServiceOptions.deprecated', index=0,
+        number=33, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.ServiceOptions.uninterpreted_option', index=1,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-FieldOptions = _reflection.GeneratedProtocolMessageType('FieldOptions', (_message.Message,), dict(
-  DESCRIPTOR = _FIELDOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions)
-  ))
-_sym_db.RegisterMessage(FieldOptions)
 
-EnumOptions = _reflection.GeneratedProtocolMessageType('EnumOptions', (_message.Message,), dict(
-  DESCRIPTOR = _ENUMOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions)
-  ))
-_sym_db.RegisterMessage(EnumOptions)
+  _METHODOPTIONS = _descriptor.Descriptor(
+    name='MethodOptions',
+    full_name='google.protobuf.MethodOptions',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='deprecated', full_name='google.protobuf.MethodOptions.deprecated', index=0,
+        number=33, type=8, cpp_type=7, label=1,
+        has_default_value=True, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='uninterpreted_option', full_name='google.protobuf.MethodOptions.uninterpreted_option', index=1,
+        number=999, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=True,
+    syntax='proto2',
+    extension_ranges=[(1000, 536870912), ],
+    oneofs=[
+    ],
+  )
 
-EnumValueOptions = _reflection.GeneratedProtocolMessageType('EnumValueOptions', (_message.Message,), dict(
-  DESCRIPTOR = _ENUMVALUEOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions)
-  ))
-_sym_db.RegisterMessage(EnumValueOptions)
 
-ServiceOptions = _reflection.GeneratedProtocolMessageType('ServiceOptions', (_message.Message,), dict(
-  DESCRIPTOR = _SERVICEOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions)
-  ))
-_sym_db.RegisterMessage(ServiceOptions)
+  _UNINTERPRETEDOPTION_NAMEPART = _descriptor.Descriptor(
+    name='NamePart',
+    full_name='google.protobuf.UninterpretedOption.NamePart',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name_part', full_name='google.protobuf.UninterpretedOption.NamePart.name_part', index=0,
+        number=1, type=9, cpp_type=9, label=2,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='is_extension', full_name='google.protobuf.UninterpretedOption.NamePart.is_extension', index=1,
+        number=2, type=8, cpp_type=7, label=2,
+        has_default_value=False, default_value=False,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
-MethodOptions = _reflection.GeneratedProtocolMessageType('MethodOptions', (_message.Message,), dict(
-  DESCRIPTOR = _METHODOPTIONS,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions)
-  ))
-_sym_db.RegisterMessage(MethodOptions)
+  _UNINTERPRETEDOPTION = _descriptor.Descriptor(
+    name='UninterpretedOption',
+    full_name='google.protobuf.UninterpretedOption',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='name', full_name='google.protobuf.UninterpretedOption.name', index=0,
+        number=2, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='identifier_value', full_name='google.protobuf.UninterpretedOption.identifier_value', index=1,
+        number=3, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='positive_int_value', full_name='google.protobuf.UninterpretedOption.positive_int_value', index=2,
+        number=4, type=4, cpp_type=4, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='negative_int_value', full_name='google.protobuf.UninterpretedOption.negative_int_value', index=3,
+        number=5, type=3, cpp_type=2, label=1,
+        has_default_value=False, default_value=0,
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='double_value', full_name='google.protobuf.UninterpretedOption.double_value', index=4,
+        number=6, type=1, cpp_type=5, label=1,
+        has_default_value=False, default_value=float(0),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='string_value', full_name='google.protobuf.UninterpretedOption.string_value', index=5,
+        number=7, type=12, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"",
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='aggregate_value', full_name='google.protobuf.UninterpretedOption.aggregate_value', index=6,
+        number=8, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[_UNINTERPRETEDOPTION_NAMEPART, ],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
-UninterpretedOption = _reflection.GeneratedProtocolMessageType('UninterpretedOption', (_message.Message,), dict(
 
-  NamePart = _reflection.GeneratedProtocolMessageType('NamePart', (_message.Message,), dict(
-    DESCRIPTOR = _UNINTERPRETEDOPTION_NAMEPART,
-    __module__ = 'google.protobuf.descriptor_pb2'
-    # @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart)
-    ))
-  ,
-  DESCRIPTOR = _UNINTERPRETEDOPTION,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption)
-  ))
-_sym_db.RegisterMessage(UninterpretedOption)
-_sym_db.RegisterMessage(UninterpretedOption.NamePart)
+  _SOURCECODEINFO_LOCATION = _descriptor.Descriptor(
+    name='Location',
+    full_name='google.protobuf.SourceCodeInfo.Location',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='path', full_name='google.protobuf.SourceCodeInfo.Location.path', index=0,
+        number=1, type=5, cpp_type=1, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='span', full_name='google.protobuf.SourceCodeInfo.Location.span', index=1,
+        number=2, type=5, cpp_type=1, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='leading_comments', full_name='google.protobuf.SourceCodeInfo.Location.leading_comments', index=2,
+        number=3, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+      _descriptor.FieldDescriptor(
+        name='trailing_comments', full_name='google.protobuf.SourceCodeInfo.Location.trailing_comments', index=3,
+        number=4, type=9, cpp_type=9, label=1,
+        has_default_value=False, default_value=b"".decode('utf-8'),
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
-SourceCodeInfo = _reflection.GeneratedProtocolMessageType('SourceCodeInfo', (_message.Message,), dict(
+  _SOURCECODEINFO = _descriptor.Descriptor(
+    name='SourceCodeInfo',
+    full_name='google.protobuf.SourceCodeInfo',
+    filename=None,
+    file=DESCRIPTOR,
+    containing_type=None,
+    create_key=_descriptor._internal_create_key,
+    fields=[
+      _descriptor.FieldDescriptor(
+        name='location', full_name='google.protobuf.SourceCodeInfo.location', index=0,
+        number=1, type=11, cpp_type=10, label=3,
+        has_default_value=False, default_value=[],
+        message_type=None, enum_type=None, containing_type=None,
+        is_extension=False, extension_scope=None,
+        serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    ],
+    extensions=[
+    ],
+    nested_types=[_SOURCECODEINFO_LOCATION, ],
+    enum_types=[
+    ],
+    serialized_options=None,
+    is_extendable=False,
+    syntax='proto2',
+    extension_ranges=[],
+    oneofs=[
+    ],
+  )
 
-  Location = _reflection.GeneratedProtocolMessageType('Location', (_message.Message,), dict(
-    DESCRIPTOR = _SOURCECODEINFO_LOCATION,
-    __module__ = 'google.protobuf.descriptor_pb2'
-    # @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location)
-    ))
-  ,
-  DESCRIPTOR = _SOURCECODEINFO,
-  __module__ = 'google.protobuf.descriptor_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo)
-  ))
-_sym_db.RegisterMessage(SourceCodeInfo)
-_sym_db.RegisterMessage(SourceCodeInfo.Location)
+  _FILEDESCRIPTORSET.fields_by_name['file'].message_type = _FILEDESCRIPTORPROTO
+  _FILEDESCRIPTORPROTO.fields_by_name['message_type'].message_type = _DESCRIPTORPROTO
+  _FILEDESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
+  _FILEDESCRIPTORPROTO.fields_by_name['service'].message_type = _SERVICEDESCRIPTORPROTO
+  _FILEDESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
+  _FILEDESCRIPTORPROTO.fields_by_name['options'].message_type = _FILEOPTIONS
+  _FILEDESCRIPTORPROTO.fields_by_name['source_code_info'].message_type = _SOURCECODEINFO
+  _DESCRIPTORPROTO_EXTENSIONRANGE.containing_type = _DESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['field'].message_type = _FIELDDESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['extension'].message_type = _FIELDDESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['nested_type'].message_type = _DESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['enum_type'].message_type = _ENUMDESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['extension_range'].message_type = _DESCRIPTORPROTO_EXTENSIONRANGE
+  _DESCRIPTORPROTO.fields_by_name['oneof_decl'].message_type = _ONEOFDESCRIPTORPROTO
+  _DESCRIPTORPROTO.fields_by_name['options'].message_type = _MESSAGEOPTIONS
+  _FIELDDESCRIPTORPROTO.fields_by_name['label'].enum_type = _FIELDDESCRIPTORPROTO_LABEL
+  _FIELDDESCRIPTORPROTO.fields_by_name['type'].enum_type = _FIELDDESCRIPTORPROTO_TYPE
+  _FIELDDESCRIPTORPROTO.fields_by_name['options'].message_type = _FIELDOPTIONS
+  _FIELDDESCRIPTORPROTO_TYPE.containing_type = _FIELDDESCRIPTORPROTO
+  _FIELDDESCRIPTORPROTO_LABEL.containing_type = _FIELDDESCRIPTORPROTO
+  _ENUMDESCRIPTORPROTO.fields_by_name['value'].message_type = _ENUMVALUEDESCRIPTORPROTO
+  _ENUMDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMOPTIONS
+  _ENUMVALUEDESCRIPTORPROTO.fields_by_name['options'].message_type = _ENUMVALUEOPTIONS
+  _SERVICEDESCRIPTORPROTO.fields_by_name['method'].message_type = _METHODDESCRIPTORPROTO
+  _SERVICEDESCRIPTORPROTO.fields_by_name['options'].message_type = _SERVICEOPTIONS
+  _METHODDESCRIPTORPROTO.fields_by_name['options'].message_type = _METHODOPTIONS
+  _FILEOPTIONS.fields_by_name['optimize_for'].enum_type = _FILEOPTIONS_OPTIMIZEMODE
+  _FILEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _FILEOPTIONS_OPTIMIZEMODE.containing_type = _FILEOPTIONS
+  _MESSAGEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _FIELDOPTIONS.fields_by_name['ctype'].enum_type = _FIELDOPTIONS_CTYPE
+  _FIELDOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _FIELDOPTIONS_CTYPE.containing_type = _FIELDOPTIONS
+  _ENUMOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _ENUMVALUEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _SERVICEOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _METHODOPTIONS.fields_by_name['uninterpreted_option'].message_type = _UNINTERPRETEDOPTION
+  _UNINTERPRETEDOPTION_NAMEPART.containing_type = _UNINTERPRETEDOPTION
+  _UNINTERPRETEDOPTION.fields_by_name['name'].message_type = _UNINTERPRETEDOPTION_NAMEPART
+  _SOURCECODEINFO_LOCATION.containing_type = _SOURCECODEINFO
+  _SOURCECODEINFO.fields_by_name['location'].message_type = _SOURCECODEINFO_LOCATION
+  DESCRIPTOR.message_types_by_name['FileDescriptorSet'] = _FILEDESCRIPTORSET
+  DESCRIPTOR.message_types_by_name['FileDescriptorProto'] = _FILEDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['DescriptorProto'] = _DESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['FieldDescriptorProto'] = _FIELDDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['OneofDescriptorProto'] = _ONEOFDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['EnumDescriptorProto'] = _ENUMDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['EnumValueDescriptorProto'] = _ENUMVALUEDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['ServiceDescriptorProto'] = _SERVICEDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['MethodDescriptorProto'] = _METHODDESCRIPTORPROTO
+  DESCRIPTOR.message_types_by_name['FileOptions'] = _FILEOPTIONS
+  DESCRIPTOR.message_types_by_name['MessageOptions'] = _MESSAGEOPTIONS
+  DESCRIPTOR.message_types_by_name['FieldOptions'] = _FIELDOPTIONS
+  DESCRIPTOR.message_types_by_name['EnumOptions'] = _ENUMOPTIONS
+  DESCRIPTOR.message_types_by_name['EnumValueOptions'] = _ENUMVALUEOPTIONS
+  DESCRIPTOR.message_types_by_name['ServiceOptions'] = _SERVICEOPTIONS
+  DESCRIPTOR.message_types_by_name['MethodOptions'] = _METHODOPTIONS
+  DESCRIPTOR.message_types_by_name['UninterpretedOption'] = _UNINTERPRETEDOPTION
+  DESCRIPTOR.message_types_by_name['SourceCodeInfo'] = _SOURCECODEINFO
+  _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
+else:
+  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.protobuf.descriptor_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
 
+  DESCRIPTOR._options = None
+  _FILEDESCRIPTORSET._serialized_start=53
+  _FILEDESCRIPTORSET._serialized_end=124
+  _FILEDESCRIPTORPROTO._serialized_start=127
+  _FILEDESCRIPTORPROTO._serialized_end=602
+  _DESCRIPTORPROTO._serialized_start=605
+  _DESCRIPTORPROTO._serialized_end=1089
+  _DESCRIPTORPROTO_EXTENSIONRANGE._serialized_start=1045
+  _DESCRIPTORPROTO_EXTENSIONRANGE._serialized_end=1089
+  _FIELDDESCRIPTORPROTO._serialized_start=1092
+  _FIELDDESCRIPTORPROTO._serialized_end=1773
+  _FIELDDESCRIPTORPROTO_TYPE._serialized_start=1394
+  _FIELDDESCRIPTORPROTO_TYPE._serialized_end=1704
+  _FIELDDESCRIPTORPROTO_LABEL._serialized_start=1706
+  _FIELDDESCRIPTORPROTO_LABEL._serialized_end=1773
+  _ONEOFDESCRIPTORPROTO._serialized_start=1775
+  _ONEOFDESCRIPTORPROTO._serialized_end=1811
+  _ENUMDESCRIPTORPROTO._serialized_start=1814
+  _ENUMDESCRIPTORPROTO._serialized_end=1954
+  _ENUMVALUEDESCRIPTORPROTO._serialized_start=1956
+  _ENUMVALUEDESCRIPTORPROTO._serialized_end=2064
+  _SERVICEDESCRIPTORPROTO._serialized_start=2067
+  _SERVICEDESCRIPTORPROTO._serialized_end=2211
+  _METHODDESCRIPTORPROTO._serialized_start=2214
+  _METHODDESCRIPTORPROTO._serialized_end=2407
+  _FILEOPTIONS._serialized_start=2410
+  _FILEOPTIONS._serialized_end=2998
+  _FILEOPTIONS_OPTIMIZEMODE._serialized_start=2929
+  _FILEOPTIONS_OPTIMIZEMODE._serialized_end=2987
+  _MESSAGEOPTIONS._serialized_start=3001
+  _MESSAGEOPTIONS._serialized_end=3231
+  _FIELDOPTIONS._serialized_start=3234
+  _FIELDOPTIONS._serialized_end=3522
+  _FIELDOPTIONS_CTYPE._serialized_start=3464
+  _FIELDOPTIONS_CTYPE._serialized_end=3511
+  _ENUMOPTIONS._serialized_start=3525
+  _ENUMOPTIONS._serialized_end=3666
+  _ENUMVALUEOPTIONS._serialized_start=3668
+  _ENUMVALUEOPTIONS._serialized_end=3793
+  _SERVICEOPTIONS._serialized_start=3795
+  _SERVICEOPTIONS._serialized_end=3918
+  _METHODOPTIONS._serialized_start=3920
+  _METHODOPTIONS._serialized_end=4042
+  _UNINTERPRETEDOPTION._serialized_start=4045
+  _UNINTERPRETEDOPTION._serialized_end=4331
+  _UNINTERPRETEDOPTION_NAMEPART._serialized_start=4280
+  _UNINTERPRETEDOPTION_NAMEPART._serialized_end=4331
+  _SOURCECODEINFO._serialized_start=4334
+  _SOURCECODEINFO._serialized_end=4511
+  _SOURCECODEINFO_LOCATION._serialized_start=4412
+  _SOURCECODEINFO_LOCATION._serialized_end=4511
 # @@protoc_insertion_point(module_scope)
diff --git a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/nanopb_pb2.py b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/nanopb_pb2.py
index ddf3569..c23077a 100644
--- a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/nanopb_pb2.py
+++ b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/nanopb_pb2.py
@@ -1,14 +1,11 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: nanopb.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf.internal import enum_type_wrapper
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
+from google.protobuf import descriptor_pool as _descriptor_pool
 from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
 # @@protoc_insertion_point(imports)
 
 _sym_db = _symbol_database.Default()
@@ -17,242 +14,22 @@
 from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='nanopb.proto',
-  package='',
-  syntax='proto2',
-  serialized_pb=_b('\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\x80\x02\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r*Z\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb')
-  ,
-  dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\x80\x02\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r*Z\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb')
 
-_FIELDTYPE = _descriptor.EnumDescriptor(
-  name='FieldType',
-  full_name='FieldType',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='FT_DEFAULT', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FT_CALLBACK', index=1, number=1,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FT_POINTER', index=2, number=4,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FT_STATIC', index=3, number=2,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='FT_IGNORE', index=4, number=3,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=309,
-  serialized_end=399,
-)
-_sym_db.RegisterEnumDescriptor(_FIELDTYPE)
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'nanopb_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+  google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt)
+  google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
+  google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
+  google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nanopb)
 
-FieldType = enum_type_wrapper.EnumTypeWrapper(_FIELDTYPE)
-_INTSIZE = _descriptor.EnumDescriptor(
-  name='IntSize',
-  full_name='IntSize',
-  filename=None,
-  file=DESCRIPTOR,
-  values=[
-    _descriptor.EnumValueDescriptor(
-      name='IS_DEFAULT', index=0, number=0,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='IS_8', index=1, number=8,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='IS_16', index=2, number=16,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='IS_32', index=3, number=32,
-      options=None,
-      type=None),
-    _descriptor.EnumValueDescriptor(
-      name='IS_64', index=4, number=64,
-      options=None,
-      type=None),
-  ],
-  containing_type=None,
-  options=None,
-  serialized_start=401,
-  serialized_end=469,
-)
-_sym_db.RegisterEnumDescriptor(_INTSIZE)
-
-IntSize = enum_type_wrapper.EnumTypeWrapper(_INTSIZE)
-FT_DEFAULT = 0
-FT_CALLBACK = 1
-FT_POINTER = 4
-FT_STATIC = 2
-FT_IGNORE = 3
-IS_DEFAULT = 0
-IS_8 = 8
-IS_16 = 16
-IS_32 = 32
-IS_64 = 64
-
-NANOPB_FILEOPT_FIELD_NUMBER = 1010
-nanopb_fileopt = _descriptor.FieldDescriptor(
-  name='nanopb_fileopt', full_name='nanopb_fileopt', index=0,
-  number=1010, type=11, cpp_type=10, label=1,
-  has_default_value=False, default_value=None,
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  options=None)
-NANOPB_MSGOPT_FIELD_NUMBER = 1010
-nanopb_msgopt = _descriptor.FieldDescriptor(
-  name='nanopb_msgopt', full_name='nanopb_msgopt', index=1,
-  number=1010, type=11, cpp_type=10, label=1,
-  has_default_value=False, default_value=None,
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  options=None)
-NANOPB_ENUMOPT_FIELD_NUMBER = 1010
-nanopb_enumopt = _descriptor.FieldDescriptor(
-  name='nanopb_enumopt', full_name='nanopb_enumopt', index=2,
-  number=1010, type=11, cpp_type=10, label=1,
-  has_default_value=False, default_value=None,
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  options=None)
-NANOPB_FIELD_NUMBER = 1010
-nanopb = _descriptor.FieldDescriptor(
-  name='nanopb', full_name='nanopb', index=3,
-  number=1010, type=11, cpp_type=10, label=1,
-  has_default_value=False, default_value=None,
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  options=None)
-
-
-_NANOPBOPTIONS = _descriptor.Descriptor(
-  name='NanoPBOptions',
-  full_name='NanoPBOptions',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='max_size', full_name='NanoPBOptions.max_size', index=0,
-      number=1, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='max_count', full_name='NanoPBOptions.max_count', index=1,
-      number=2, type=5, cpp_type=1, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='int_size', full_name='NanoPBOptions.int_size', index=2,
-      number=7, type=14, cpp_type=8, label=1,
-      has_default_value=True, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='type', full_name='NanoPBOptions.type', index=3,
-      number=3, type=14, cpp_type=8, label=1,
-      has_default_value=True, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='long_names', full_name='NanoPBOptions.long_names', index=4,
-      number=4, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=True,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='packed_struct', full_name='NanoPBOptions.packed_struct', index=5,
-      number=5, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='skip_message', full_name='NanoPBOptions.skip_message', index=6,
-      number=6, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='no_unions', full_name='NanoPBOptions.no_unions', index=7,
-      number=8, type=8, cpp_type=7, label=1,
-      has_default_value=True, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='msgid', full_name='NanoPBOptions.msgid', index=8,
-      number=9, type=13, cpp_type=3, label=1,
-      has_default_value=False, default_value=0,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=51,
-  serialized_end=307,
-)
-
-_NANOPBOPTIONS.fields_by_name['int_size'].enum_type = _INTSIZE
-_NANOPBOPTIONS.fields_by_name['type'].enum_type = _FIELDTYPE
-DESCRIPTOR.message_types_by_name['NanoPBOptions'] = _NANOPBOPTIONS
-DESCRIPTOR.enum_types_by_name['FieldType'] = _FIELDTYPE
-DESCRIPTOR.enum_types_by_name['IntSize'] = _INTSIZE
-DESCRIPTOR.extensions_by_name['nanopb_fileopt'] = nanopb_fileopt
-DESCRIPTOR.extensions_by_name['nanopb_msgopt'] = nanopb_msgopt
-DESCRIPTOR.extensions_by_name['nanopb_enumopt'] = nanopb_enumopt
-DESCRIPTOR.extensions_by_name['nanopb'] = nanopb
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-NanoPBOptions = _reflection.GeneratedProtocolMessageType('NanoPBOptions', (_message.Message,), dict(
-  DESCRIPTOR = _NANOPBOPTIONS,
-  __module__ = 'nanopb_pb2'
-  # @@protoc_insertion_point(class_scope:NanoPBOptions)
-  ))
-_sym_db.RegisterMessage(NanoPBOptions)
-
-nanopb_fileopt.message_type = _NANOPBOPTIONS
-google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt)
-nanopb_msgopt.message_type = _NANOPBOPTIONS
-google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
-nanopb_enumopt.message_type = _NANOPBOPTIONS
-google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
-nanopb.message_type = _NANOPBOPTIONS
-google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nanopb)
-
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\030fi.kapsi.koti.jpa.nanopb'))
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n\030fi.kapsi.koti.jpa.nanopb'
+  _FIELDTYPE._serialized_start=309
+  _FIELDTYPE._serialized_end=399
+  _INTSIZE._serialized_start=401
+  _INTSIZE._serialized_end=469
+  _NANOPBOPTIONS._serialized_start=51
+  _NANOPBOPTIONS._serialized_end=307
 # @@protoc_insertion_point(module_scope)
diff --git a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/plugin_pb2.py b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/plugin_pb2.py
index d693863..79fffcd 100644
--- a/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/plugin_pb2.py
+++ b/acts/framework/acts/controllers/buds_lib/dev_utils/proto/gen/plugin_pb2.py
@@ -1,13 +1,11 @@
+# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: plugin.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
 from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
+from google.protobuf import descriptor_pool as _descriptor_pool
 from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
 # @@protoc_insertion_point(imports)
 
 _sym_db = _symbol_database.Default()
@@ -16,173 +14,18 @@
 from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='plugin.proto',
-  package='google.protobuf.compiler',
-  syntax='proto2',
-  serialized_pb=_b('\n\x0cplugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"}\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xaa\x01\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a>\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\tB,\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtos')
-  ,
-  dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cplugin.proto\x12\x18google.protobuf.compiler\x1a google/protobuf/descriptor.proto\"}\n\x14\x43odeGeneratorRequest\x12\x18\n\x10\x66ile_to_generate\x18\x01 \x03(\t\x12\x11\n\tparameter\x18\x02 \x01(\t\x12\x38\n\nproto_file\x18\x0f \x03(\x0b\x32$.google.protobuf.FileDescriptorProto\"\xaa\x01\n\x15\x43odeGeneratorResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\t\x12\x42\n\x04\x66ile\x18\x0f \x03(\x0b\x32\x34.google.protobuf.compiler.CodeGeneratorResponse.File\x1a>\n\x04\x46ile\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0finsertion_point\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x0f \x01(\tB,\n\x1c\x63om.google.protobuf.compilerB\x0cPluginProtos')
 
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'plugin_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
 
-
-
-_CODEGENERATORREQUEST = _descriptor.Descriptor(
-  name='CodeGeneratorRequest',
-  full_name='google.protobuf.compiler.CodeGeneratorRequest',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='file_to_generate', full_name='google.protobuf.compiler.CodeGeneratorRequest.file_to_generate', index=0,
-      number=1, type=9, cpp_type=9, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='parameter', full_name='google.protobuf.compiler.CodeGeneratorRequest.parameter', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='proto_file', full_name='google.protobuf.compiler.CodeGeneratorRequest.proto_file', index=2,
-      number=15, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=76,
-  serialized_end=201,
-)
-
-
-_CODEGENERATORRESPONSE_FILE = _descriptor.Descriptor(
-  name='File',
-  full_name='google.protobuf.compiler.CodeGeneratorResponse.File',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='name', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.name', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='insertion_point', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point', index=1,
-      number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='content', full_name='google.protobuf.compiler.CodeGeneratorResponse.File.content', index=2,
-      number=15, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=312,
-  serialized_end=374,
-)
-
-_CODEGENERATORRESPONSE = _descriptor.Descriptor(
-  name='CodeGeneratorResponse',
-  full_name='google.protobuf.compiler.CodeGeneratorResponse',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='error', full_name='google.protobuf.compiler.CodeGeneratorResponse.error', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-    _descriptor.FieldDescriptor(
-      name='file', full_name='google.protobuf.compiler.CodeGeneratorResponse.file', index=1,
-      number=15, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[_CODEGENERATORRESPONSE_FILE, ],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  syntax='proto2',
-  extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=204,
-  serialized_end=374,
-)
-
-_CODEGENERATORREQUEST.fields_by_name['proto_file'].message_type = google_dot_protobuf_dot_descriptor__pb2._FILEDESCRIPTORPROTO
-_CODEGENERATORRESPONSE_FILE.containing_type = _CODEGENERATORRESPONSE
-_CODEGENERATORRESPONSE.fields_by_name['file'].message_type = _CODEGENERATORRESPONSE_FILE
-DESCRIPTOR.message_types_by_name['CodeGeneratorRequest'] = _CODEGENERATORREQUEST
-DESCRIPTOR.message_types_by_name['CodeGeneratorResponse'] = _CODEGENERATORRESPONSE
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-CodeGeneratorRequest = _reflection.GeneratedProtocolMessageType('CodeGeneratorRequest', (_message.Message,), dict(
-  DESCRIPTOR = _CODEGENERATORREQUEST,
-  __module__ = 'plugin_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
-  ))
-_sym_db.RegisterMessage(CodeGeneratorRequest)
-
-CodeGeneratorResponse = _reflection.GeneratedProtocolMessageType('CodeGeneratorResponse', (_message.Message,), dict(
-
-  File = _reflection.GeneratedProtocolMessageType('File', (_message.Message,), dict(
-    DESCRIPTOR = _CODEGENERATORRESPONSE_FILE,
-    __module__ = 'plugin_pb2'
-    # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
-    ))
-  ,
-  DESCRIPTOR = _CODEGENERATORRESPONSE,
-  __module__ = 'plugin_pb2'
-  # @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
-  ))
-_sym_db.RegisterMessage(CodeGeneratorResponse)
-_sym_db.RegisterMessage(CodeGeneratorResponse.File)
-
-
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\034com.google.protobuf.compilerB\014PluginProtos'))
+  DESCRIPTOR._options = None
+  DESCRIPTOR._serialized_options = b'\n\034com.google.protobuf.compilerB\014PluginProtos'
+  _CODEGENERATORREQUEST._serialized_start=76
+  _CODEGENERATORREQUEST._serialized_end=201
+  _CODEGENERATORRESPONSE._serialized_start=204
+  _CODEGENERATORRESPONSE._serialized_end=374
+  _CODEGENERATORRESPONSE_FILE._serialized_start=312
+  _CODEGENERATORRESPONSE_FILE._serialized_end=374
 # @@protoc_insertion_point(module_scope)
diff --git a/acts/framework/acts/controllers/buds_lib/tako_trace_logger.py b/acts/framework/acts/controllers/buds_lib/tako_trace_logger.py
index ff31840..a9d8afe 100644
--- a/acts/framework/acts/controllers/buds_lib/tako_trace_logger.py
+++ b/acts/framework/acts/controllers/buds_lib/tako_trace_logger.py
@@ -53,4 +53,3 @@
         Note that flushing the log is handled automatically by python's logging
         module.
         """
-        pass
diff --git a/acts/framework/acts/controllers/cellular_lib/AndroidCellularDut.py b/acts/framework/acts/controllers/cellular_lib/AndroidCellularDut.py
index be3056a..0e2d86f 100644
--- a/acts/framework/acts/controllers/cellular_lib/AndroidCellularDut.py
+++ b/acts/framework/acts/controllers/cellular_lib/AndroidCellularDut.py
@@ -16,8 +16,15 @@
 
 from acts.controllers.android_lib.tel import tel_utils
 from acts.controllers.cellular_lib import BaseCellularDut
+import os
+import time
 
 GET_BUILD_VERSION = 'getprop ro.build.version.release'
+PIXELLOGGER_CONTROL = 'am broadcast -n com.android.pixellogger/.receiver.' \
+                      'AlwaysOnLoggingReceiver -a com.android.pixellogger.' \
+                      'service.logging.LoggingService.' \
+                      'ACTION_CONFIGURE_ALWAYS_ON_LOGGING ' \
+                      '-e intent_key_enable "{}"'
 
 NETWORK_TYPE_TO_BITMASK = {
     BaseCellularDut.PreferredNetworkType.LTE_ONLY: '01000001000000000000',
@@ -36,6 +43,8 @@
         """
         self.ad = ad
         self.log = logger
+        logger.info('Initializing Android DUT with baseband version {}'.format(
+            ad.adb.getprop('gsm.version.baseband')))
 
     def toggle_airplane_mode(self, new_state=True):
         """ Turns airplane mode on / off.
@@ -80,15 +89,18 @@
           type: an instance of class PreferredNetworkType
         """
 
+        self.log.info('setting preferred network type: {}'.format(type))
         # If android version is S or later, uses bit mask to set and return.
         version = self.ad.adb.shell(GET_BUILD_VERSION)
+        self.log.info('The android version is {}'.format(version))
         try:
             version_in_number = int(version)
             if version_in_number > 11:
-                set_network_cmd = 'cmd phone set-allowed-network-types-for-users '
-                set_network_cmd += NETWORK_TYPE_TO_BITMASK[type]
+                base_cmd = 'cmd phone set-allowed-network-types-for-users -s 0 '
+                set_network_cmd = base_cmd + NETWORK_TYPE_TO_BITMASK[type]
                 self.ad.adb.shell(set_network_cmd)
-                get_network_cmd = 'cmd phone get-allowed-network-types-for-users'
+                get_network_cmd = ('cmd phone '
+                                   'get-allowed-network-types-for-users -s 0')
                 allowed_network = self.ad.adb.shell(get_network_cmd)
                 self.log.info('The allowed network: {}'.format(allowed_network))
                 return
@@ -115,3 +127,33 @@
 
         Will be deprecated and replaced by get_rx_tx_power_levels. """
         tel_utils.get_telephony_signal_strength(self.ad)
+
+    def start_modem_logging(self):
+        """ Starts on-device log collection. """
+        self.ad.adb.shell('rm /data/vendor/slog/*.* -f')
+        self.ad.adb.shell(PIXELLOGGER_CONTROL.format('true'))
+
+    def stop_modem_logging(self):
+        """ Stops log collection and pulls logs. """
+        output_path = self.ad.device_log_path + '/modem/'
+        os.makedirs(output_path, exist_ok=True)
+        self.ad.adb.shell(PIXELLOGGER_CONTROL.format('false'))
+
+    def toggle_data(self, new_state=True):
+        """ Turns on/off of the cellular data.
+
+        Args:
+            new_state: True to enable cellular data
+        """
+        self.log.info('Toggles cellular data on: {}'.format(new_state))
+        if new_state:
+            self.ad.adb.shell('settings put global mobile_data 1')
+            self.ad.adb.shell('svc data enable')
+            time.sleep(5)
+            self.log.info('global mobile data: {}'.format(
+                self.ad.adb.shell('settings get global mobile_data')))
+        else:
+            self.ad.adb.shell('settings put global mobile_data 0')
+            self.ad.adb.shell('svc data disable')
+            self.log.info('global mobile data: {}'.format(
+                self.ad.adb.shell('settings get global mobile_data')))
diff --git a/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py b/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py
index 14540de..9869264 100644
--- a/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py
+++ b/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py
@@ -46,5 +46,5 @@
             new_config: 5G cell configuration object.
         """
         for attr, value in vars(new_config).items():
-            if value and not hasattr(self, attr):
+            if value is not None:
                 setattr(self, attr, value)
diff --git a/acts/framework/acts/controllers/cellular_lib/BaseCellularDut.py b/acts/framework/acts/controllers/cellular_lib/BaseCellularDut.py
index 5bdbc1c..0bf6170 100644
--- a/acts/framework/acts/controllers/cellular_lib/BaseCellularDut.py
+++ b/acts/framework/acts/controllers/cellular_lib/BaseCellularDut.py
@@ -77,3 +77,11 @@
 
         Will be deprecated and replaced by get_rx_tx_power_levels. """
         raise NotImplementedError()
+
+    def start_modem_logging(self):
+        """ Starts on-device log collection. """
+        raise NotImplementedError()
+
+    def stop_modem_logging(self):
+        """ Stops log collection and pulls logs. """
+        raise NotImplementedError()
\ No newline at end of file
diff --git a/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py b/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
index 5e53786..8332584 100644
--- a/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
@@ -68,9 +68,13 @@
     # the simulations inheriting from this class.
     DOWNLINK_SIGNAL_LEVEL_UNITS = None
 
-    def __init__(
-        self, simulator, log, dut, test_config, calibration_table,
-        nr_mode=None):
+    def __init__(self,
+                 simulator,
+                 log,
+                 dut,
+                 test_config,
+                 calibration_table,
+                 nr_mode=None):
         """ Initializes the Simulation object.
 
         Keeps a reference to the callbox, log and dut handlers and
@@ -739,3 +743,11 @@
             Maximum throughput in mbps
         """
         raise NotImplementedError()
+
+    def send_sms(self, message):
+        """ Sends an SMS message to the DUT.
+
+        Args:
+            message: the SMS message to send.
+        """
+        raise NotImplementedError()
diff --git a/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py b/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py
index 34b982d..6d47087 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py
@@ -113,6 +113,9 @@
         self.drx_long_cycle = None
         self.drx_long_cycle_offset = None
 
+    def __str__(self):
+        return str(vars(self))
+
     def configure(self, parameters):
         """ Configures an LTE cell using a dictionary of parameters.
 
diff --git a/acts/framework/acts/controllers/cellular_lib/LteImsSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteImsSimulation.py
index a47988e..e011478 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteImsSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteImsSimulation.py
@@ -43,7 +43,9 @@
         # Make sure the IMS registration was successful by verifying the CSCF
         # status is SIP IDLE.
         if not _wait_for_ims_cscf_status(
-                self.log, self.anritsu, DEFAULT_IMS_VIRTUAL_NETWORK_ID,
+                self.log,
+                self.simulator.anritsu,
+                DEFAULT_IMS_VIRTUAL_NETWORK_ID,
                 md8475a.ImsCscfStatus.SIPIDLE.value):
             self.log.error('UE failed to register with the IMS server.')
             return False
diff --git a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
index 346046c..250a0d1 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
@@ -22,6 +22,13 @@
 from acts.controllers.cellular_lib import BaseCellularDut
 
 
+class IPAddressType(Enum):
+    """ IP Address types"""
+    IPV4 = "IPV4"
+    IPV6 = "IPV6"
+    IPV4V6 = "IPV4V6"
+
+
 class TransmissionMode(Enum):
     """ Transmission modes for LTE (e.g., TM1, TM4, ...) """
     TM1 = "TM1"
@@ -87,7 +94,7 @@
     # RSRP signal levels thresholds (as reported by Android) in dBm/15KHz.
     # Excellent is set to -75 since callbox B Tx power is limited to -30 dBm
     DOWNLINK_SIGNAL_LEVEL_DICTIONARY = {
-        'excellent': -75,
+        'excellent': -62,
         'high': -110,
         'medium': -115,
         'weak': -120,
@@ -411,9 +418,13 @@
         tdd_config4_tput_lut  # DL 256QAM, UL 64 QAM OFF & MAC padding ON
     }
 
-    def __init__(
-        self, simulator, log, dut, test_config, calibration_table,
-        nr_mode=None):
+    def __init__(self,
+                 simulator,
+                 log,
+                 dut,
+                 test_config,
+                 calibration_table,
+                 nr_mode=None):
         """ Initializes the simulator for a single-carrier LTE simulation.
 
         Args:
@@ -426,8 +437,8 @@
 
         """
 
-        super().__init__(
-            simulator, log, dut, test_config, calibration_table, nr_mode)
+        super().__init__(simulator, log, dut, test_config, calibration_table,
+                         nr_mode)
 
         self.num_carriers = None
 
@@ -435,14 +446,14 @@
         try:
             if self.nr_mode and 'nr' == self.nr_mode:
                 self.dut.set_preferred_network_type(
-                    BaseCellularDut.PreferredNetworkType.LTE_NR)
+                    BaseCellularDut.PreferredNetworkType.NR_LTE)
             else:
                 self.dut.set_preferred_network_type(
                     BaseCellularDut.PreferredNetworkType.LTE_ONLY)
         except Exception as e:
             # If this fails the test should be able to run anyways, even if it
             # takes longer to find the cell.
-            self.log.warning('Setting preferred RAT failed: ' + str(e))
+            self.log.warning('Setting preferred RAT failed: {}'.format(e))
 
         # Get LTE CA frequency bands setting from the test configuration
         if self.KEY_FREQ_BANDS not in test_config:
@@ -512,17 +523,32 @@
                     new_cell_list.append(dict(cell))
                     bw = int(cell[LteCellConfig.PARAM_BW])
                     dl_earfcn = LteCellConfig.PARAM_DL_EARFCN
-                    new_cell_list[-1][dl_earfcn] = self.LOWEST_DL_CN_DICTIONARY[
-                        int(band_num)] + bw * 10 - 2
+                    new_cell_list[-1][
+                        dl_earfcn] = self.LOWEST_DL_CN_DICTIONARY[int(
+                            band_num)] + bw * 10 - 2
             else:
                 # The band is just a number, so just add it to the list
                 new_cell_list.append(cell)
 
+        # verify mimo mode parameter is provided
+        for cell in new_cell_list:
+            if not LteCellConfig.PARAM_MIMO in cell:
+                raise ValueError(
+                    'The config dictionary must include parameter "{}" with the'
+                    ' mimo mode.'.format(self.PARAM_MIMO))
+
+            if cell[LteCellConfig.PARAM_MIMO] not in (m.value
+                                                      for m in MimoMode):
+                raise ValueError(
+                    'The value of {} must be one of the following:'
+                    '1x1, 2x2 or 4x4.'.format(self.PARAM_MIMO))
+
         # Logs new_cell_list for debug
         self.log.info('new cell list: {}'.format(new_cell_list))
 
         self.simulator.set_band_combination(
-            [c[LteCellConfig.PARAM_BAND] for c in new_cell_list])
+            [c[LteCellConfig.PARAM_BAND] for c in new_cell_list],
+            [MimoMode(c[LteCellConfig.PARAM_MIMO]) for c in new_cell_list])
 
         self.num_carriers = len(new_cell_list)
 
@@ -604,7 +630,7 @@
 
         bandwidth = bts_config.bandwidth
 
-        if bandwidth == 100: # This assumes 273 RBs. TODO: b/229163022
+        if bandwidth == 100:  # This assumes 273 RBs. TODO: b/229163022
             power = rsrp + 35.15
         elif bandwidth == 20:  # 100 RBs
             power = rsrp + 30.79
@@ -921,3 +947,11 @@
                     self.cell_configs[bts_index].incorporate(new_config)
 
             self.simulator.lte_attach_secondary_carriers(self.freq_bands)
+
+    def send_sms(self, message):
+        """ Sends an SMS message to the DUT.
+
+        Args:
+            message: the SMS message to send.
+        """
+        self.simulator.send_sms(message)
diff --git a/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py b/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py
index 5a18025..7eef6fb 100644
--- a/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py
+++ b/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py
@@ -15,6 +15,7 @@
 #   limitations under the License.
 
 import acts.controllers.cellular_lib.BaseCellConfig as base_cell
+import acts.controllers.cellular_lib.LteSimulation as lte_sim
 
 
 class NrCellConfig(base_cell.BaseCellConfig):
@@ -25,8 +26,18 @@
         bandwidth: a integer indicating the required channel bandwidth
     """
 
-    PARAM_BAND = "band"
-    PARAM_BW = "bw"
+    PARAM_BAND = 'band'
+    PARAM_BW = 'bw'
+    PARAM_DL_MCS = 'dlmcs'
+    PARAM_DL_RBS = 'dl_rbs'
+    PARAM_PADDING = 'mac_padding'
+    PARAM_MIMO = 'mimo'
+    PARAM_NRARFCN = 'nr_arfcn'
+    PARAM_SCHEDULING = "scheduling"
+    PARAM_SCHEDULING_DYNAMIC = "dynamic"
+    PARAM_SCHEDULING_STATIC = "static"
+    PARAM_UL_MCS = 'ulmcs'
+    PARAM_UL_RBS = 'ul_rbs'
 
     def __init__(self, log):
         """ Initialize the base station config by setting all its
@@ -37,6 +48,13 @@
         super().__init__(log)
         self.band = None
         self.bandwidth = None
+        self.dl_rbs = None
+        self.ul_rbs = None
+        self.dl_mcs = None
+        self.ul_mcs = None
+        self.mac_padding = None
+        self.mimo_mode = None
+        self.nr_arfcn = None
 
     def configure(self, parameters):
         """ Configures an NR cell using a dictionary of parameters.
@@ -48,13 +66,72 @@
             raise ValueError(
                 "The configuration dictionary must include a key '{}' with "
                 "the required band number.".format(self.PARAM_BAND))
+        nr_band = parameters[self.PARAM_BAND]
+        if nr_band[0] == 'n':
+            nr_band = nr_band[1:]
+        self.band = nr_band
 
-        self.band = parameters[self.PARAM_BAND]
+        if self.PARAM_NRARFCN in parameters:
+            self.nr_arfcn = int(parameters[self.PARAM_NRARFCN])
 
         if self.PARAM_BW not in parameters:
             raise ValueError(
                 "The config dictionary must include parameter {} with an "
                 "int value (to indicate 1.4 MHz use 14).".format(
                     self.PARAM_BW))
+        bw = float(parameters[self.PARAM_BW])
 
-        self.bandwidth = parameters[self.PARAM_BW]
+        if abs(bw - 14) < 0.00000000001:
+            bw = 1.4
+
+        self.bandwidth = bw
+
+        # Setup mimo mode
+        if self.PARAM_MIMO not in parameters:
+            raise ValueError(
+                "The config dictionary must include parameter '{}' with the "
+                "mimo mode.".format(self.PARAM_MIMO))
+
+        for mimo_mode in lte_sim.MimoMode:
+            if parameters[self.PARAM_MIMO] == mimo_mode.value:
+                self.mimo_mode = mimo_mode
+                break
+        else:
+            raise ValueError("The value of {} must be one of the following:"
+                             "1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
+
+        if self.PARAM_SCHEDULING not in parameters:
+            self.scheduling_mode = lte_sim.SchedulingMode.STATIC
+            self.log.warning(
+                "The test config does not include the '{}' key. Setting to "
+                "static by default.".format(self.PARAM_SCHEDULING))
+        elif parameters[
+                self.PARAM_SCHEDULING] == self.PARAM_SCHEDULING_DYNAMIC:
+            self.scheduling_mode = lte_sim.SchedulingMode.DYNAMIC
+        elif parameters[self.PARAM_SCHEDULING] == self.PARAM_SCHEDULING_STATIC:
+            self.scheduling_mode = lte_sim.SchedulingMode.STATIC
+        else:
+            raise ValueError("Key '{}' must have a value of "
+                             "'dynamic' or 'static'.".format(
+                                 self.PARAM_SCHEDULING))
+
+        if self.scheduling_mode == lte_sim.SchedulingMode.STATIC:
+
+            if self.PARAM_PADDING not in parameters:
+                self.log.warning(
+                    "The '{}' parameter was not set. Enabling MAC padding by "
+                    "default.".format(self.PARAM_PADDING))
+                self.mac_padding = True
+
+            if self.PARAM_DL_MCS in parameters:
+                self.dl_mcs = int(parameters[self.PARAM_DL_MCS])
+
+            if self.PARAM_UL_MCS in parameters:
+                self.ul_mcs = int(parameters[self.PARAM_UL_MCS])
+
+            # Temproraily setting: set 273 for bandwidth of 100 MHz
+            self.dl_rbs = 273
+            self.ul_rbs = 273
+
+    def __str__(self):
+        return str(vars(self))
diff --git a/acts/framework/acts/controllers/cellular_lib/OWNERS b/acts/framework/acts/controllers/cellular_lib/OWNERS
index e4010df..f88a96c 100644
--- a/acts/framework/acts/controllers/cellular_lib/OWNERS
+++ b/acts/framework/acts/controllers/cellular_lib/OWNERS
@@ -1,4 +1,8 @@
 iguarna@google.com
 chaoyangf@google.com
 yixiang@google.com
-codycaldwell@google.com
\ No newline at end of file
+codycaldwell@google.com
+
+per-file PresetSimulation.py = hmtuan@google.com
+per-file PresetSimulation.py = harjani@google.com
+per-file PresetSimulation.py = jethier@google.com
\ No newline at end of file
diff --git a/acts/framework/acts/controllers/cellular_lib/PresetSimulation.py b/acts/framework/acts/controllers/cellular_lib/PresetSimulation.py
new file mode 100644
index 0000000..d536b09
--- /dev/null
+++ b/acts/framework/acts/controllers/cellular_lib/PresetSimulation.py
@@ -0,0 +1,245 @@
+#   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.
+#   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.
+
+from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation
+from acts.controllers.cellular_lib import BaseCellularDut
+
+
+class PresetSimulation(BaseSimulation):
+    """5G preset simulation.
+
+    The simulation will be configed by importing SCPI config file
+    instead of individually set params.
+    """
+
+    # Keys to obtain settings from the test_config dictionary.
+    KEY_CELL_INFO = "cell_info"
+    KEY_SCPI_FILE_NAME = "scpi_file"
+
+    NETWORK_BIT_MASK = {
+        'nr_lte': '11000001000000000000'
+    }
+    ADB_CMD_LOCK_NETWORK = 'cmd phone set-allowed-network-types-for-users -s 0 {network_bit_mask}'
+    NR_LTE_BIT_MASK_KEY = 'nr_lte'
+
+    def __init__(self,
+                 simulator,
+                 log,
+                 dut,
+                 test_config,
+                 calibration_table,
+                 nr_mode=None):
+        """Initializes the simulator for 5G preset simulation.
+
+        Args:
+            simulator: a cellular simulator controller.
+            log: a logger handle.
+            dut: a device handler implementing BaseCellularDut.
+            test_config: test configuration obtained from the config file.
+            calibration_table: a dictionary containing path losses
+                for different bands.
+        """
+
+        super().__init__(simulator, log, dut, test_config, calibration_table,
+                         nr_mode)
+        # require param for idle test case
+        self.rrc_sc_timer = 0
+
+        # Set to KeySight APN
+        log.info('Configuring APN.')
+        self.dut.set_apn('Keysight', 'Keysight')
+        self.num_carriers = None
+
+        # Enable roaming on the phone
+        self.dut.toggle_data_roaming(True)
+
+    def setup_simulator(self):
+        """Do initial configuration in the simulator. """
+        self.log.info('This simulation does not require initial setup.')
+
+    def configure(self, parameters):
+        """Configures simulation by importing scpi file.
+
+        A pre-made SCPI file include all the essential configuration
+        for the simulation is imported by send SCPI import command
+        to the callbox.
+
+        Args:
+            parameters: a configuration dictionary which includes scpi file path
+                if there is only one carrier, a list if there are multiple cells.
+        """
+        scpi_file = parameters[0][self.KEY_SCPI_FILE_NAME]
+        cell_infos = parameters[0][self.KEY_CELL_INFO]
+
+        self.log.info('Configure test scenario with\n' +
+                      f' SCPI config file: {scpi_file}\n' +
+                      f' cell info: {cell_infos}')
+
+        self.simulator.import_configuration(scpi_file)
+        self.simulator.set_cell_info(cell_infos)
+
+    def start(self):
+        """Start simulation.
+
+        Waiting for the DUT to connect to the callbox.
+
+        Raise:
+            RuntimeError: simulation fail to start
+                due to unable to connect dut and cells.
+        """
+        self.attach()
+
+    def attach(self):
+        """Attach UE to the callbox.
+
+        Toggle airplane mode on-off and wait for a specified timeout,
+        repeat until the UE connect to the callbox.
+
+        Raise:
+            RuntimeError: attaching fail
+                due to unable to connect dut and cells.
+        """
+        try:
+            self.simulator.wait_until_attached(self.dut, self.attach_timeout,
+                                               self.attach_retries)
+        except Exception as exc:
+            raise RuntimeError('Could not attach to base station.') from exc
+
+    def calibrated_downlink_rx_power(self, bts_config, rsrp):
+        """Convert RSRP to total signal power from the basestation.
+
+        Args:
+            bts_config: the current configuration at the base station
+            rsrp: desired rsrp, contained in a key value pair
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def downlink_calibration(self, rat=None, power_units_conversion_func=None):
+        """Computes downlink path loss and returns the calibration value.
+
+        See base class implementation for details.
+
+        Args:
+            rat: ignored, replaced by 'lteRsrp'.
+            power_units_conversion_func: ignored, replaced by
+                self.rsrp_to_signal_power.
+
+        Returns:
+            Downlink calibration value and measured DL power. Note that the
+            phone only reports RSRP of the primary chain
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def rsrp_to_signal_power(self, rsrp, bts_config):
+        """Converts rsrp to total band signal power
+
+        RSRP is measured per subcarrier, so total band power needs to be
+        multiplied by the number of subcarriers being used.
+
+        Args:
+            rsrp: desired rsrp in dBm.
+            bts_config: a base station configuration object.
+
+        Returns:
+            Total band signal power in dBm
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def maximum_downlink_throughput(self):
+        """Calculates maximum achievable downlink throughput in.
+
+        The calculation is based on the current simulation state
+        Returns:
+            Maximum throughput in mbps.
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def bts_maximum_downlink_throughtput(self, bts_config):
+        """Calculates maximum achievable downlink throughput for a single
+
+        base station from its configuration object.
+
+        Args:
+            bts_config: a base station configuration object.
+
+        Returns:
+            Maximum throughput in mbps.
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def maximum_uplink_throughput(self):
+        """Calculates maximum achievable uplink throughput.
+
+        Returns:
+            Maximum throughput in mbps.
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def bts_maximum_uplink_throughtput(self, bts_config):
+        """Calculates maximum achievable uplink throughput
+
+        The calculation is for selected basestation
+        from its configuration object.
+        Args:
+            bts_config: an LTE base station configuration object.
+
+        Returns:
+            Maximum throughput in mbps.
+
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def calibrate(self, band):
+        """Calculates UL and DL path loss if it wasn't done before
+
+        Before running the base class implementation, configure the base station
+        to only use one downlink antenna with maximum bandwidth.
+
+        Args:
+            band: the band that is currently being calibrated.
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def start_traffic_for_calibration(self):
+        """If MAC padding is enabled, there is no need to start IP traffic. """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def stop_traffic_for_calibration(self):
+        """If MAC padding is enabled, IP traffic wasn't started. """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
+
+    def get_measured_ul_power(self, samples=5, wait_after_sample=3):
+        """Calculates UL power.
+
+        The calculation is based on measurements from the callbox
+        and the calibration data.
+        Args:
+            samples: the numble of samples to average
+            wait_after_sample: time in seconds to wait in between samples
+
+        Returns:
+            the ul power at the UE antenna ports in dBs
+        """
+        raise NotImplementedError(
+            'This simulation mode does not support this configuration option')
diff --git a/acts/framework/acts/controllers/cellular_simulator.py b/acts/framework/acts/controllers/cellular_simulator.py
index 0a026e6..471b14a 100644
--- a/acts/framework/acts/controllers/cellular_simulator.py
+++ b/acts/framework/acts/controllers/cellular_simulator.py
@@ -45,11 +45,12 @@
         """ Configures the equipment for an LTE simulation. """
         raise NotImplementedError()
 
-    def set_band_combination(self, bands):
-        """ Prepares the test equipment for the indicated CA combination.
+    def set_band_combination(self, bands, mimo_modes):
+        """ Prepares the test equipment for the indicated band/mimo combination.
 
         Args:
             bands: a list of bands represented as ints or strings
+            mimo_modes: a list of LteSimulation.MimoMode to use for each antenna
         """
         raise NotImplementedError()
 
@@ -63,6 +64,13 @@
             bts_index: the base station number.
         """
 
+        config_vars = vars(config)
+        config_dict = {
+            key: config_vars[key]
+            for key in config_vars if config_vars[key]
+        }
+        self.log.info('The config for {} is {}'.format(bts_index, config_dict))
+
         if config.output_power:
             self.set_output_power(bts_index, config.output_power)
 
@@ -72,6 +80,9 @@
         if isinstance(config, cellular_lib.LteCellConfig.LteCellConfig):
             self.configure_lte_bts(config, bts_index)
 
+        if isinstance(config, cellular_lib.NrCellConfig.NrCellConfig):
+            self.configure_nr_bts(config, bts_index)
+
     def configure_lte_bts(self, config, bts_index=0):
         """ Commands the equipment to setup an LTE base station with the
         required configuration.
@@ -111,8 +122,8 @@
 
         if config.scheduling_mode:
 
-            if (config.scheduling_mode ==
-                    cellular_lib.LteSimulation.SchedulingMode.STATIC
+            if (config.scheduling_mode
+                    == cellular_lib.LteSimulation.SchedulingMode.STATIC
                     and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
                              and config.ul_mcs)):
                 raise ValueError('When the scheduling mode is set to manual, '
@@ -160,6 +171,43 @@
                 self.set_drx_long_cycle_offset(bts_index,
                                                config.drx_long_cycle_offset)
 
+    def configure_nr_bts(self, config, bts_index=1):
+        """ Commands the equipment to setup an LTE base station with the
+        required configuration.
+
+        Args:
+            config: an LteSimulation.BtsConfig object.
+            bts_index: the base station number.
+        """
+        if config.band:
+            self.set_band(bts_index, config.band)
+
+        if config.nr_arfcn:
+            self.set_downlink_channel_number(bts_index, config.nr_arfcn)
+
+        if config.bandwidth:
+            self.set_bandwidth(bts_index, config.bandwidth)
+
+        if config.mimo_mode:
+            self.set_mimo_mode(bts_index, config.mimo_mode)
+
+        if config.scheduling_mode:
+
+            if (config.scheduling_mode
+                    == cellular_lib.LteSimulation.SchedulingMode.STATIC
+                    and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
+                             and config.ul_mcs)):
+                raise ValueError('When the scheduling mode is set to manual, '
+                                 'the RB and MCS parameters are required.')
+
+            # If scheduling mode is set to Dynamic, the RB and MCS parameters
+            # will be ignored by set_scheduling_mode.
+            self.set_scheduling_mode(bts_index, config.scheduling_mode,
+                                     config.dl_mcs, config.ul_mcs,
+                                     config.dl_rbs, config.ul_rbs)
+        if config.mac_padding is not None:
+            self.set_mac_padding(bts_index, config.mac_padding)
+
     def set_lte_rrc_state_change_timer(self, enabled, time=10):
         """ Configures the LTE RRC state change timer.
 
@@ -380,6 +428,30 @@
         """
         raise NotImplementedError()
 
+    def set_apn(self, apn):
+        """ Configures the callbox network Access Point Name.
+
+        Args:
+            apn: the APN name
+        """
+        raise NotImplementedError()
+
+    def set_ip_type(self, ip_type):
+        """ Configures the callbox network IP type.
+
+        Args:
+            ip_type: the network type to use.
+        """
+        raise NotImplementedError()
+
+    def set_mtu(self, mtu):
+        """ Configures the callbox network Maximum Transmission Unit.
+
+        Args:
+            mtu: the MTU size.
+        """
+        raise NotImplementedError()
+
     def lte_attach_secondary_carriers(self, ue_capability_enquiry):
         """ Activates the secondary carriers for CA. Requires the DUT to be
         attached to the primary carrier first.
@@ -417,6 +489,15 @@
         """
         raise NotImplementedError()
 
+    def wait_until_quiet(self, timeout=120):
+        """Waits for all pending operations to finish on the simulator.
+
+        Args:
+            timeout: after this amount of time the method will raise a
+                CellularSimulatorError exception. Default is 120 seconds.
+        """
+        raise NotImplementedError()
+
     def detach(self):
         """ Turns off all the base stations so the DUT loose connection."""
         raise NotImplementedError()
@@ -442,8 +523,15 @@
         """
         raise NotImplementedError()
 
+    def send_sms(self, message):
+        """ Sends an SMS message to the DUT.
+
+        Args:
+            message: the SMS message to send.
+        """
+        raise NotImplementedError()
+
 
 class CellularSimulatorError(Exception):
     """ Exceptions thrown when the cellular equipment is unreachable or it
     returns an error after receiving a command. """
-    pass
diff --git a/acts/framework/acts/controllers/chameleon_controller.py b/acts/framework/acts/controllers/chameleon_controller.py
index b9965cf..ed21934 100644
--- a/acts/framework/acts/controllers/chameleon_controller.py
+++ b/acts/framework/acts/controllers/chameleon_controller.py
@@ -15,7 +15,6 @@
 #   limitations under the License.
 
 import logging
-import time
 import xmlrpc.client
 from subprocess import call
 
@@ -105,8 +104,9 @@
         self.port = port
         self.address = "http://{}:{}".format(ip, self.port)
         try:
-            self.client = xmlrpc.client.ServerProxy(
-                self.address, allow_none=True, verbose=False)
+            self.client = xmlrpc.client.ServerProxy(self.address,
+                                                    allow_none=True,
+                                                    verbose=False)
         except ConnectionRefusedError as err:
             self.log.exception(
                 "Failed to connect to Chameleon Device at: {}".format(
diff --git a/acts/framework/acts/controllers/fastboot.py b/acts/framework/acts/controllers/fastboot.py
index 6f47255..db31a19 100755
--- a/acts/framework/acts/controllers/fastboot.py
+++ b/acts/framework/acts/controllers/fastboot.py
@@ -16,7 +16,6 @@
 
 from acts.libs.proc import job
 
-import logging
 from acts import error
 
 
@@ -73,8 +72,10 @@
         if ret == 0 or ignore_status:
             return out
         else:
-            raise FastbootError(
-                cmd=command, stdout=out, stderr=err, ret_code=ret)
+            raise FastbootError(cmd=command,
+                                stdout=out,
+                                stderr=err,
+                                ret_code=ret)
 
     def args(self, *args, **kwargs):
         return job.run(' '.join((self.fastboot_str, ) + args), **kwargs).stdout
diff --git a/acts/framework/acts/controllers/fuchsia_device.py b/acts/framework/acts/controllers/fuchsia_device.py
index a42a722..99d5752 100644
--- a/acts/framework/acts/controllers/fuchsia_device.py
+++ b/acts/framework/acts/controllers/fuchsia_device.py
@@ -14,14 +14,11 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import backoff
+from typing import Optional
 import json
 import logging
 import os
-import random
 import re
-import requests
-import socket
 import subprocess
 import time
 
@@ -31,45 +28,16 @@
 from acts import utils
 from acts.controllers import pdu
 from acts.libs.proc import job
-from acts.utils import get_fuchsia_mdns_ipv6_address
+from acts.utils import get_fuchsia_mdns_ipv6_address, get_interface_ip_addresses
 
-from acts.controllers.fuchsia_lib.audio_lib import FuchsiaAudioLib
-from acts.controllers.fuchsia_lib.backlight_lib import FuchsiaBacklightLib
-from acts.controllers.fuchsia_lib.basemgr_lib import FuchsiaBasemgrLib
-from acts.controllers.fuchsia_lib.bt.avdtp_lib import FuchsiaAvdtpLib
-from acts.controllers.fuchsia_lib.bt.ble_lib import FuchsiaBleLib
-from acts.controllers.fuchsia_lib.bt.bts_lib import FuchsiaBtsLib
-from acts.controllers.fuchsia_lib.bt.gattc_lib import FuchsiaGattcLib
-from acts.controllers.fuchsia_lib.bt.gatts_lib import FuchsiaGattsLib
-from acts.controllers.fuchsia_lib.bt.hfp_lib import FuchsiaHfpLib
-from acts.controllers.fuchsia_lib.bt.rfcomm_lib import FuchsiaRfcommLib
-from acts.controllers.fuchsia_lib.bt.sdp_lib import FuchsiaProfileServerLib
 from acts.controllers.fuchsia_lib.ffx import FFX
-from acts.controllers.fuchsia_lib.gpio_lib import FuchsiaGpioLib
-from acts.controllers.fuchsia_lib.hardware_power_statecontrol_lib import FuchsiaHardwarePowerStatecontrolLib
-from acts.controllers.fuchsia_lib.hwinfo_lib import FuchsiaHwinfoLib
-from acts.controllers.fuchsia_lib.i2c_lib import FuchsiaI2cLib
-from acts.controllers.fuchsia_lib.input_report_lib import FuchsiaInputReportLib
-from acts.controllers.fuchsia_lib.kernel_lib import FuchsiaKernelLib
+from acts.controllers.fuchsia_lib.sl4f import SL4F
 from acts.controllers.fuchsia_lib.lib_controllers.netstack_controller import NetstackController
 from acts.controllers.fuchsia_lib.lib_controllers.wlan_controller import WlanController
 from acts.controllers.fuchsia_lib.lib_controllers.wlan_policy_controller import WlanPolicyController
-from acts.controllers.fuchsia_lib.light_lib import FuchsiaLightLib
-from acts.controllers.fuchsia_lib.location.regulatory_region_lib import FuchsiaRegulatoryRegionLib
-from acts.controllers.fuchsia_lib.logging_lib import FuchsiaLoggingLib
-from acts.controllers.fuchsia_lib.netstack.netstack_lib import FuchsiaNetstackLib
-from acts.controllers.fuchsia_lib.ram_lib import FuchsiaRamLib
-from acts.controllers.fuchsia_lib.session_manager_lib import FuchsiaSessionManagerLib
-from acts.controllers.fuchsia_lib.sysinfo_lib import FuchsiaSysInfoLib
-from acts.controllers.fuchsia_lib.syslog_lib import FuchsiaSyslogError
-from acts.controllers.fuchsia_lib.syslog_lib import create_syslog_process
-from acts.controllers.fuchsia_lib.utils_lib import SshResults
-from acts.controllers.fuchsia_lib.utils_lib import create_ssh_connection
+from acts.controllers.fuchsia_lib.package_server import PackageServer
+from acts.controllers.fuchsia_lib.ssh import DEFAULT_SSH_PORT, DEFAULT_SSH_USER, SSHConfig, SSHProvider, FuchsiaSSHError
 from acts.controllers.fuchsia_lib.utils_lib import flash
-from acts.controllers.fuchsia_lib.wlan_ap_policy_lib import FuchsiaWlanApPolicyLib
-from acts.controllers.fuchsia_lib.wlan_deprecated_configuration_lib import FuchsiaWlanDeprecatedConfigurationLib
-from acts.controllers.fuchsia_lib.wlan_lib import FuchsiaWlanLib
-from acts.controllers.fuchsia_lib.wlan_policy_lib import FuchsiaWlanPolicyLib
 
 MOBLY_CONTROLLER_CONFIG_NAME = "FuchsiaDevice"
 ACTS_CONTROLLER_REFERENCE_NAME = "fuchsia_devices"
@@ -83,11 +51,7 @@
 FUCHSIA_DEVICE_NO_IP_MSG = "No IP address specified, abort!"
 FUCHSIA_COULD_NOT_GET_DESIRED_STATE = "Could not %s %s."
 FUCHSIA_INVALID_CONTROL_STATE = "Invalid control state (%s). abort!"
-FUCHSIA_SSH_CONFIG_NOT_DEFINED = ("Cannot send ssh commands since the "
-                                  "ssh_config was not specified in the Fuchsia"
-                                  "device config.")
 
-FUCHSIA_SSH_USERNAME = "fuchsia"
 FUCHSIA_TIME_IN_NANOSECONDS = 1000000000
 
 SL4F_APK_NAME = "com.googlecode.android_scripting"
@@ -96,25 +60,15 @@
 DAEMON_ACTIVATED_STATES = ["running", "start"]
 DAEMON_DEACTIVATED_STATES = ["stop", "stopped"]
 
-FUCHSIA_DEFAULT_LOG_CMD = 'iquery --absolute_paths --cat --format= --recursive'
-FUCHSIA_DEFAULT_LOG_ITEMS = [
-    '/hub/c/scenic.cmx/[0-9]*/out/objects',
-    '/hub/c/root_presenter.cmx/[0-9]*/out/objects',
-    '/hub/c/wlanstack2.cmx/[0-9]*/out/public',
-    '/hub/c/basemgr.cmx/[0-9]*/out/objects'
-]
-
 FUCHSIA_RECONNECT_AFTER_REBOOT_TIME = 5
 
 CHANNEL_OPEN_TIMEOUT = 5
 
-FUCHSIA_GET_VERSION_CMD = 'cat /config/build-info/version'
-
 FUCHSIA_REBOOT_TYPE_SOFT = 'soft'
 FUCHSIA_REBOOT_TYPE_SOFT_AND_FLASH = 'flash'
 FUCHSIA_REBOOT_TYPE_HARD = 'hard'
 
-FUCHSIA_DEFAULT_CONNECT_TIMEOUT = 60
+FUCHSIA_DEFAULT_CONNECT_TIMEOUT = 90
 FUCHSIA_DEFAULT_COMMAND_TIMEOUT = 60
 
 FUCHSIA_DEFAULT_CLEAN_UP_COMMAND_TIMEOUT = 15
@@ -125,12 +79,17 @@
 MDNS_LOOKUP_RETRY_MAX = 3
 
 VALID_ASSOCIATION_MECHANISMS = {None, 'policy', 'drivers'}
+IP_ADDRESS_TIMEOUT = 15
 
 
 class FuchsiaDeviceError(signals.ControllerError):
     pass
 
 
+class FuchsiaConfigError(signals.ControllerError):
+    """Incorrect FuchsiaDevice configuration."""
+
+
 def create(configs):
     if not configs:
         raise FuchsiaDeviceError(FUCHSIA_DEVICE_EMPTY_CONFIG_MSG)
@@ -212,23 +171,34 @@
         self.conf_data = fd_conf_data
         if "ip" not in fd_conf_data:
             raise FuchsiaDeviceError(FUCHSIA_DEVICE_NO_IP_MSG)
-        self.ip = fd_conf_data["ip"]
-        self.orig_ip = fd_conf_data["ip"]
-        self.sl4f_port = fd_conf_data.get("sl4f_port", 80)
-        self.ssh_port = fd_conf_data.get("ssh_port", 22)
-        self.ssh_config = fd_conf_data.get("ssh_config", None)
-        self.ssh_priv_key = fd_conf_data.get("ssh_priv_key", None)
-        self.authorized_file = fd_conf_data.get("authorized_file_loc", None)
-        self.serial_number = fd_conf_data.get("serial_number", None)
-        self.device_type = fd_conf_data.get("device_type", None)
-        self.product_type = fd_conf_data.get("product_type", None)
-        self.board_type = fd_conf_data.get("board_type", None)
-        self.build_number = fd_conf_data.get("build_number", None)
-        self.build_type = fd_conf_data.get("build_type", None)
-        self.server_path = fd_conf_data.get("server_path", None)
-        self.specific_image = fd_conf_data.get("specific_image", None)
-        self.ffx_binary_path = fd_conf_data.get("ffx_binary_path", None)
-        self.mdns_name = fd_conf_data.get("mdns_name", None)
+        self.ip: str = fd_conf_data["ip"]
+        self.orig_ip: str = fd_conf_data["ip"]
+        self.sl4f_port: int = fd_conf_data.get("sl4f_port", 80)
+        self.ssh_port: int = fd_conf_data.get("ssh_port", DEFAULT_SSH_PORT)
+        self.ssh_config: Optional[str] = fd_conf_data.get("ssh_config", None)
+        self.ssh_priv_key: Optional[str] = fd_conf_data.get(
+            "ssh_priv_key", None)
+        self.authorized_file: Optional[str] = fd_conf_data.get(
+            "authorized_file_loc", None)
+        self.serial_number: Optional[str] = fd_conf_data.get(
+            "serial_number", None)
+        self.device_type: Optional[str] = fd_conf_data.get("device_type", None)
+        self.product_type: Optional[str] = fd_conf_data.get(
+            "product_type", None)
+        self.board_type: Optional[str] = fd_conf_data.get("board_type", None)
+        self.build_number: Optional[str] = fd_conf_data.get(
+            "build_number", None)
+        self.build_type: Optional[str] = fd_conf_data.get("build_type", None)
+        self.server_path: Optional[str] = fd_conf_data.get("server_path", None)
+        self.specific_image: Optional[str] = fd_conf_data.get(
+            "specific_image", None)
+        self.ffx_binary_path: Optional[str] = fd_conf_data.get(
+            "ffx_binary_path", None)
+        # Path to a tar.gz archive with pm and amber-files, as necessary for
+        # starting a package server.
+        self.packages_archive_path: Optional[str] = fd_conf_data.get(
+            "packages_archive_path", None)
+        self.mdns_name: Optional[str] = fd_conf_data.get("mdns_name", None)
 
         # Instead of the input ssh_config, a new config is generated with proper
         # ControlPath to the test output directory.
@@ -238,8 +208,7 @@
         self._set_control_path_config(self.ssh_config, generated_ssh_config)
         self.ssh_config = generated_ssh_config
 
-        self.ssh_username = fd_conf_data.get("ssh_username",
-                                             FUCHSIA_SSH_USERNAME)
+        self.ssh_username = fd_conf_data.get("ssh_username", DEFAULT_SSH_USER)
         self.hard_reboot_on_fail = fd_conf_data.get("hard_reboot_on_fail",
                                                     False)
         self.take_bug_report_on_fail = fd_conf_data.get(
@@ -247,7 +216,6 @@
         self.device_pdu_config = fd_conf_data.get("PduDevice", None)
         self.config_country_code = fd_conf_data.get(
             'country_code', FUCHSIA_DEFAULT_COUNTRY_CODE_US).upper()
-        self._persistent_ssh_conn = None
 
         # WLAN interface info is populated inside configure_wlan
         self.wlan_client_interfaces = {}
@@ -269,11 +237,8 @@
         self.default_preserve_saved_networks = fd_conf_data.get(
             'preserve_saved_networks', True)
 
-        if utils.is_valid_ipv4_address(self.ip):
-            self.address = "http://{}:{}".format(self.ip, self.sl4f_port)
-        elif utils.is_valid_ipv6_address(self.ip):
-            self.address = "http://[{}]:{}".format(self.ip, self.sl4f_port)
-        else:
+        if not utils.is_valid_ipv4_address(
+                self.ip) and not utils.is_valid_ipv6_address(self.ip):
             mdns_ip = None
             for retry_counter in range(MDNS_LOOKUP_RETRY_MAX):
                 mdns_ip = get_fuchsia_mdns_ipv6_address(self.ip)
@@ -286,22 +251,14 @@
                 # unless one was explicitly provided.
                 self.mdns_name = self.mdns_name or self.ip
                 self.ip = mdns_ip
-                self.address = "http://[{}]:{}".format(self.ip, self.sl4f_port)
             else:
                 raise ValueError('Invalid IP: %s' % self.ip)
 
         self.log = acts_logger.create_tagged_trace_logger(
             "FuchsiaDevice | %s" % self.orig_ip)
 
-        self.init_address = self.address + "/init"
-        self.cleanup_address = self.address + "/cleanup"
-        self.print_address = self.address + "/print_clients"
         self.ping_rtt_match = re.compile(r'RTT Min/Max/Avg '
                                          r'= \[ (.*?) / (.*?) / (.*?) \] ms')
-
-        # TODO(): Come up with better client numbering system
-        self.client_id = "FuchsiaClient" + str(random.randint(0, 1000000))
-        self.test_counter = 0
         self.serial = re.sub('[.:%]', '_', self.ip)
         log_path_base = getattr(logging, 'log_path', '/tmp/logs')
         self.log_path = os.path.join(log_path_base,
@@ -309,19 +266,79 @@
         self.fuchsia_log_file_path = os.path.join(
             self.log_path, "fuchsialog_%s_debug.txt" % self.serial)
         self.log_process = None
+        self.package_server = None
 
-        self.init_libraries()
+        self.init_controllers()
 
-        self.setup_commands = fd_conf_data.get('setup_commands', [])
-        self.teardown_commands = fd_conf_data.get('teardown_commands', [])
+    @property
+    def sl4f(self):
+        """Get the sl4f module configured for this device.
 
-        try:
-            self.start_services()
-            self.run_commands_from_config(self.setup_commands)
-        except Exception as e:
-            # Prevent a threading error, since controller isn't fully up yet.
-            self.clean_up()
-            raise e
+        The sl4f module uses lazy-initialization; it will initialize an sl4f
+        server on the host device when it is required.
+        """
+        if not hasattr(self, '_sl4f'):
+            self._sl4f = SL4F(self.ssh, self.sl4f_port)
+            self.log.info('Started SL4F server')
+        return self._sl4f
+
+    @sl4f.deleter
+    def sl4f(self):
+        if not hasattr(self, '_sl4f'):
+            return
+        del self._sl4f
+
+    @property
+    def ssh(self):
+        """Get the SSH provider module configured for this device."""
+        if not hasattr(self, '_ssh'):
+            if not self.ssh_port:
+                raise FuchsiaConfigError(
+                    'Must provide "ssh_port: <int>" in the device config')
+            if not self.ssh_priv_key:
+                raise FuchsiaConfigError(
+                    'Must provide "ssh_priv_key: <file path>" in the device config'
+                )
+            self._ssh = SSHProvider(
+                SSHConfig(self.ip, self.ssh_priv_key, port=self.ssh_port))
+        return self._ssh
+
+    @ssh.deleter
+    def ssh(self):
+        if not hasattr(self, '_ssh'):
+            return
+        del self._ssh
+
+    @property
+    def ffx(self):
+        """Get the ffx module configured for this device.
+
+        The ffx module uses lazy-initialization; it will initialize an ffx
+        connection to the device when it is required.
+
+        If ffx needs to be reinitialized, delete the "ffx" property and attempt
+        access again. Note re-initialization will interrupt any running ffx
+        calls.
+        """
+        if not hasattr(self, '_ffx'):
+            if not self.ffx_binary_path:
+                raise FuchsiaConfigError(
+                    'Must provide "ffx_binary_path: <path to FFX binary>" in the device config'
+                )
+            if not self.mdns_name:
+                raise FuchsiaConfigError(
+                    'Must provide "mdns_name: <device mDNS name>" in the device config'
+                )
+            self._ffx = FFX(self.ffx_binary_path, self.mdns_name, self.ip,
+                            self.ssh_priv_key)
+        return self._ffx
+
+    @ffx.deleter
+    def ffx(self):
+        if not hasattr(self, '_ffx'):
+            return
+        self._ffx.clean_up()
+        del self._ffx
 
     def _set_control_path_config(self, old_config, new_config):
         """Given an input ssh_config, write to a new config with proper
@@ -344,121 +361,7 @@
         with open(new_config, 'w') as file:
             file.write(ssh_config_copy)
 
-    def init_libraries(self):
-        # Grab commands from FuchsiaAudioLib
-        self.audio_lib = FuchsiaAudioLib(self.address, self.test_counter,
-                                         self.client_id)
-
-        # Grab commands from FuchsiaAvdtpLib
-        self.avdtp_lib = FuchsiaAvdtpLib(self.address, self.test_counter,
-                                         self.client_id)
-
-        # Grab commands from FuchsiaHfpLib
-        self.hfp_lib = FuchsiaHfpLib(self.address, self.test_counter,
-                                     self.client_id)
-
-        # Grab commands from FuchsiaRfcommLib
-        self.rfcomm_lib = FuchsiaRfcommLib(self.address, self.test_counter,
-                                           self.client_id)
-
-        # Grab commands from FuchsiaLightLib
-        self.light_lib = FuchsiaLightLib(self.address, self.test_counter,
-                                         self.client_id)
-
-        # Grab commands from FuchsiaBacklightLib
-        self.backlight_lib = FuchsiaBacklightLib(self.address,
-                                                 self.test_counter,
-                                                 self.client_id)
-
-        # Grab commands from FuchsiaBasemgrLib
-        self.basemgr_lib = FuchsiaBasemgrLib(self.address, self.test_counter,
-                                             self.client_id)
-        # Grab commands from FuchsiaBleLib
-        self.ble_lib = FuchsiaBleLib(self.address, self.test_counter,
-                                     self.client_id)
-        # Grab commands from FuchsiaBtsLib
-        self.bts_lib = FuchsiaBtsLib(self.address, self.test_counter,
-                                     self.client_id)
-        # Grab commands from FuchsiaGattcLib
-        self.gattc_lib = FuchsiaGattcLib(self.address, self.test_counter,
-                                         self.client_id)
-        # Grab commands from FuchsiaGattsLib
-        self.gatts_lib = FuchsiaGattsLib(self.address, self.test_counter,
-                                         self.client_id)
-
-        # Grab commands from FuchsiaGpioLib
-        self.gpio_lib = FuchsiaGpioLib(self.address, self.test_counter,
-                                       self.client_id)
-
-        # Grab commands from FuchsiaHardwarePowerStatecontrolLib
-        self.hardware_power_statecontrol_lib = (
-            FuchsiaHardwarePowerStatecontrolLib(self.address,
-                                                self.test_counter,
-                                                self.client_id))
-
-        # Grab commands from FuchsiaHwinfoLib
-        self.hwinfo_lib = FuchsiaHwinfoLib(self.address, self.test_counter,
-                                           self.client_id)
-
-        # Grab commands from FuchsiaI2cLib
-        self.i2c_lib = FuchsiaI2cLib(self.address, self.test_counter,
-                                     self.client_id)
-
-        # Grab commands from FuchsiaInputReportLib
-        self.input_report_lib = FuchsiaInputReportLib(self.address,
-                                                      self.test_counter,
-                                                      self.client_id)
-
-        # Grab commands from FuchsiaKernelLib
-        self.kernel_lib = FuchsiaKernelLib(self.address, self.test_counter,
-                                           self.client_id)
-
-        # Grab commands from FuchsiaLoggingLib
-        self.logging_lib = FuchsiaLoggingLib(self.address, self.test_counter,
-                                             self.client_id)
-
-        # Grab commands from FuchsiaNetstackLib
-        self.netstack_lib = FuchsiaNetstackLib(self.address, self.test_counter,
-                                               self.client_id)
-
-        # Grab commands from FuchsiaLightLib
-        self.ram_lib = FuchsiaRamLib(self.address, self.test_counter,
-                                     self.client_id)
-
-        # Grab commands from FuchsiaProfileServerLib
-        self.sdp_lib = FuchsiaProfileServerLib(self.address, self.test_counter,
-                                               self.client_id)
-
-        # Grab commands from FuchsiaRegulatoryRegionLib
-        self.regulatory_region_lib = FuchsiaRegulatoryRegionLib(
-            self.address, self.test_counter, self.client_id)
-
-        # Grab commands from FuchsiaSysInfoLib
-        self.sysinfo_lib = FuchsiaSysInfoLib(self.address, self.test_counter,
-                                             self.client_id)
-
-        # Grab commands from FuchsiaSessionManagerLib
-        self.session_manager_lib = FuchsiaSessionManagerLib(self)
-
-        # Grabs command from FuchsiaWlanDeprecatedConfigurationLib
-        self.wlan_deprecated_configuration_lib = (
-            FuchsiaWlanDeprecatedConfigurationLib(self.address,
-                                                  self.test_counter,
-                                                  self.client_id))
-
-        # Grab commands from FuchsiaWlanLib
-        self.wlan_lib = FuchsiaWlanLib(self.address, self.test_counter,
-                                       self.client_id)
-
-        # Grab commands from FuchsiaWlanApPolicyLib
-        self.wlan_ap_policy_lib = FuchsiaWlanApPolicyLib(
-            self.address, self.test_counter, self.client_id)
-
-        # Grab commands from FuchsiaWlanPolicyLib
-        self.wlan_policy_lib = FuchsiaWlanPolicyLib(self.address,
-                                                    self.test_counter,
-                                                    self.client_id)
-
+    def init_controllers(self):
         # Contains Netstack functions
         self.netstack_controller = NetstackController(self)
 
@@ -466,49 +369,27 @@
         self.wlan_controller = WlanController(self)
 
         # Contains WLAN policy functions like save_network, remove_network, etc
-        self.wlan_policy_controller = WlanPolicyController(self)
+        self.wlan_policy_controller = WlanPolicyController(self.sl4f, self.ffx)
 
-    @backoff.on_exception(
-        backoff.constant,
-        (ConnectionRefusedError, requests.exceptions.ConnectionError),
-        interval=1.5,
-        max_tries=4)
-    def init_sl4f_connection(self):
-        """Initializes HTTP connection with SL4F server."""
-        self.log.debug("Initializing SL4F server connection")
-        init_data = json.dumps({
-            "jsonrpc": "2.0",
-            "id": self.build_id(self.test_counter),
-            "method": "sl4f.sl4f_init",
-            "params": {
-                "client_id": self.client_id
-            }
-        })
-
-        requests.get(url=self.init_address, data=init_data)
-        self.test_counter += 1
-
-    def init_ffx_connection(self):
-        """Initializes ffx's connection to the device.
-
-        If ffx has already been initialized, it will be reinitialized. This will
-        break any running tests calling ffx for this device.
-        """
-        self.log.debug("Initializing ffx connection")
-
-        if not self.ffx_binary_path:
-            raise ValueError(
-                'Must provide "ffx_binary_path: <path to FFX binary>" in the device config'
+    def start_package_server(self):
+        if not self.packages_archive_path:
+            self.log.warn(
+                "packages_archive_path is not specified. "
+                "Assuming a package server is already running and configured on "
+                "the DUT. If this is not the case, either run your own package "
+                "server, or configure these fields appropriately. "
+                "This is usually required for the Fuchsia iPerf3 client or "
+                "other testing utilities not on device cache.")
+            return
+        if self.package_server:
+            self.log.warn(
+                "Skipping to start the package server since is already running"
             )
-        if not self.mdns_name:
-            raise ValueError(
-                'Must provide "mdns_name: <device mDNS name>" in the device config'
-            )
+            return
 
-        if hasattr(self, 'ffx'):
-            self.ffx.clean_up()
-
-        self.ffx = FFX(self.ffx_binary_path, self.mdns_name, self.ssh_priv_key)
+        self.package_server = PackageServer(self.packages_archive_path)
+        self.package_server.start()
+        self.package_server.configure_device(self.ssh)
 
     def run_commands_from_config(self, cmd_dicts):
         """Runs commands on the Fuchsia device from the config file. Useful for
@@ -519,6 +400,10 @@
                 'cmd': string, command to run on device
                 'timeout': int, seconds to wait for command to run (optional)
                 'skip_status_code_check': bool, disregard errors if true
+
+        Raises:
+            FuchsiaDeviceError: if any of the commands return a non-zero status
+                code and skip_status_code_check is false or undefined.
         """
         for cmd_dict in cmd_dicts:
             try:
@@ -533,29 +418,19 @@
             skip_status_code_check = 'true' == str(
                 cmd_dict.get('skip_status_code_check', False)).lower()
 
-            self.log.info(
-                'Running command "%s".%s' %
-                (cmd, ' Ignoring result.' if skip_status_code_check else ''))
-            result = self.send_command_ssh(
-                cmd,
-                timeout=timeout,
-                skip_status_code_check=skip_status_code_check)
+            if skip_status_code_check:
+                self.log.info(f'Running command "{cmd}" and ignoring result.')
+            else:
+                self.log.info(f'Running command "{cmd}".')
 
-            if isinstance(result, Exception):
-                raise result
-
-            elif not skip_status_code_check and result.stderr:
-                raise FuchsiaDeviceError(
-                    'Error when running command "%s": %s' %
-                    (cmd, result.stderr))
-
-    def build_id(self, test_id):
-        """Concatenates client_id and test_id to form a command_id
-
-        Args:
-            test_id: string, unique identifier of test command
-        """
-        return self.client_id + "." + str(test_id)
+            try:
+                result = self.ssh.run(cmd, timeout_sec=timeout)
+                self.log.debug(result)
+            except FuchsiaSSHError as e:
+                if not skip_status_code_check:
+                    raise FuchsiaDeviceError(
+                        'Failed device specific commands for initial configuration'
+                    ) from e
 
     def configure_wlan(self,
                        association_mechanism=None,
@@ -593,6 +468,7 @@
 
         # Allows for wlan to be set up differently in different tests
         if self.association_mechanism:
+            self.log.info('Deconfiguring WLAN')
             self.deconfigure_wlan()
 
         self.association_mechanism = association_mechanism
@@ -612,8 +488,7 @@
         else:
             # This requires SL4F calls, so it can only happen with actual
             # devices, not with unit tests.
-            self.wlan_policy_controller._configure_wlan(
-                preserve_saved_networks)
+            self.wlan_policy_controller.configure_wlan(preserve_saved_networks)
 
         # Retrieve WLAN client and AP interfaces
         self.wlan_controller.update_wlan_interfaces()
@@ -639,139 +514,84 @@
         self.association_mechanism = None
 
     def reboot(self,
-               use_ssh=False,
-               unreachable_timeout=FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
-               ping_timeout=FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
-               ssh_timeout=FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
-               reboot_type=FUCHSIA_REBOOT_TYPE_SOFT,
-               testbed_pdus=None):
+               use_ssh: bool = False,
+               unreachable_timeout: int = FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
+               ping_timeout: int = FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
+               ssh_timeout: int = FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
+               reboot_type: int = FUCHSIA_REBOOT_TYPE_SOFT,
+               testbed_pdus: list[pdu.PduDevice] = None) -> None:
         """Reboot a FuchsiaDevice.
 
         Soft reboots the device, verifies it becomes unreachable, then verifies
         it comes back online. Re-initializes services so the tests can continue.
 
         Args:
-            use_ssh: bool, if True, use fuchsia shell command via ssh to reboot
+            use_ssh: if True, use fuchsia shell command via ssh to reboot
                 instead of SL4F.
-            unreachable_timeout: int, time to wait for device to become
-                unreachable.
-            ping_timeout: int, time to wait for device to respond to pings.
-            ssh_timeout: int, time to wait for device to be reachable via ssh.
-            reboot_type: boolFUCHSIA_REBOOT_TYPE_SOFT or
-                FUCHSIA_REBOOT_TYPE_HARD
-            testbed_pdus: list, all testbed PDUs
+            unreachable_timeout: time to wait for device to become unreachable.
+            ping_timeout:time to wait for device to respond to pings.
+            ssh_timeout: time to wait for device to be reachable via ssh.
+            reboot_type: 'soft', 'hard' or 'flash'.
+            testbed_pdus: all testbed PDUs.
 
         Raises:
-            ConnectionError, if device fails to become unreachable, fails to
-                come back up, or if SL4F does not setup correctly.
+            ConnectionError, if device fails to become unreachable or fails to
+                come back up.
         """
-        skip_unreachable_check = False
-        # Call Reboot
         if reboot_type == FUCHSIA_REBOOT_TYPE_SOFT:
             if use_ssh:
-                self.log.info('Sending reboot command via SSH.')
-                with utils.SuppressLogOutput():
-                    self.clean_up_services()
-                    self.send_command_ssh(
+                self.log.info('Soft rebooting via SSH')
+                try:
+                    self.ssh.run(
                         'dm reboot',
-                        timeout=FUCHSIA_RECONNECT_AFTER_REBOOT_TIME,
-                        skip_status_code_check=True)
+                        timeout_sec=FUCHSIA_RECONNECT_AFTER_REBOOT_TIME)
+                except FuchsiaSSHError as e:
+                    if 'closed by remote host' not in e.result.stderr:
+                        raise e
             else:
-                self.log.info('Calling SL4F reboot command.')
-                with utils.SuppressLogOutput():
-                    self.hardware_power_statecontrol_lib.suspendReboot(
-                        timeout=3)
-                    self.clean_up_services()
-        elif reboot_type == FUCHSIA_REBOOT_TYPE_SOFT_AND_FLASH:
-            flash(self, use_ssh, FUCHSIA_RECONNECT_AFTER_REBOOT_TIME)
-            skip_unreachable_check = True
+                self.log.info('Soft rebooting via SL4F')
+                self.sl4f.hardware_power_statecontrol_lib.suspendReboot(
+                    timeout=3)
+            self._check_unreachable(timeout_sec=unreachable_timeout)
+
         elif reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
-            self.log.info('Power cycling FuchsiaDevice (%s)' % self.ip)
+            self.log.info('Hard rebooting via PDU')
             if not testbed_pdus:
                 raise AttributeError('Testbed PDUs must be supplied '
                                      'to hard reboot a fuchsia_device.')
             device_pdu, device_pdu_port = pdu.get_pdu_port_for_device(
                 self.device_pdu_config, testbed_pdus)
-            with utils.SuppressLogOutput():
-                self.clean_up_services()
-            self.log.info('Killing power to FuchsiaDevice (%s)...' % self.ip)
+            self.log.info('Killing power to FuchsiaDevice')
             device_pdu.off(str(device_pdu_port))
-        else:
-            raise ValueError('Invalid reboot type: %s' % reboot_type)
-        if not skip_unreachable_check:
-            # Wait for unreachable
-            self.log.info('Verifying device is unreachable.')
-            timeout = time.time() + unreachable_timeout
-            while (time.time() < timeout):
-                if utils.can_ping(job, self.ip):
-                    self.log.debug('Device is still pingable. Retrying.')
-                else:
-                    if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
-                        self.log.info(
-                            'Restoring power to FuchsiaDevice (%s)...' %
-                            self.ip)
-                        device_pdu.on(str(device_pdu_port))
-                    break
-            else:
-                self.log.info(
-                    'Device failed to go offline. Restarting services...')
-                self.start_services()
-                raise ConnectionError('Device never went down.')
-            self.log.info('Device is unreachable as expected.')
-        if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
-            self.log.info('Restoring power to FuchsiaDevice (%s)...' % self.ip)
+            self._check_unreachable(timeout_sec=unreachable_timeout)
+            self.log.info('Restoring power to FuchsiaDevice')
             device_pdu.on(str(device_pdu_port))
 
-        self.log.info('Waiting for device to respond to pings.')
-        end_time = time.time() + ping_timeout
-        while time.time() < end_time:
-            if utils.can_ping(job, self.ip):
-                break
-            else:
-                self.log.debug('Device is not pingable. Retrying in 1 second.')
-                time.sleep(1)
+        elif reboot_type == FUCHSIA_REBOOT_TYPE_SOFT_AND_FLASH:
+            flash(self, use_ssh, FUCHSIA_RECONNECT_AFTER_REBOOT_TIME)
+
         else:
-            raise ConnectionError('Device never came back online.')
-        self.log.info('Device responded to pings.')
+            raise ValueError('Invalid reboot type: %s' % reboot_type)
+
+        self._check_reachable(timeout_sec=ping_timeout)
+
+        # Cleanup services
+        self.stop_services()
 
         self.log.info('Waiting for device to allow ssh connection.')
         end_time = time.time() + ssh_timeout
         while time.time() < end_time:
             try:
-                self.send_command_ssh('\n')
-            except Exception:
-                self.log.debug(
-                    'Could not SSH to device. Retrying in 1 second.')
-                time.sleep(1)
+                self.ssh.run('echo')
+            except Exception as e:
+                self.log.debug(f'Retrying SSH to device. Details: {e}')
             else:
                 break
         else:
             raise ConnectionError('Failed to connect to device via SSH.')
         self.log.info('Device now available via ssh.')
 
-        # Creating new log process, start it, start new persistent ssh session,
-        # start SL4F, and connect via SL4F
-        self.log.info(f'Restarting services on FuchsiaDevice {self.ip}')
-        self.start_services()
-
-        # Verify SL4F is up.
-        self.log.info('Verifying SL4F commands can run.')
-        try:
-            self.hwinfo_lib.getDeviceInfo()
-        except Exception as err:
-            raise ConnectionError(
-                'Failed to connect and run command via SL4F. Err: %s' % err)
-
-        # Reconfigure country code, as it does not persist after reboots
-        self.configure_regulatory_domain(self.config_country_code)
-        try:
-            self.run_commands_from_config(self.setup_commands)
-        except FuchsiaDeviceError:
-            # Prevent a threading error, since controller isn't fully up yet.
-            self.clean_up()
-            raise FuchsiaDeviceError(
-                'Failed to run setup commands after reboot.')
-
+        # TODO (b/246852449): Move configure_wlan to other controllers.
         # If wlan was configured before reboot, it must be configured again
         # after rebooting, as it was before reboot. No preserving should occur.
         if self.association_mechanism:
@@ -782,68 +602,39 @@
                 association_mechanism=pre_reboot_association_mechanism,
                 preserve_saved_networks=False)
 
-        self.log.info(
-            'Device has rebooted, SL4F is reconnected and functional.')
+        self.log.info('Device has rebooted')
 
-    def send_command_ssh(self,
-                         test_cmd,
-                         connect_timeout=FUCHSIA_DEFAULT_CONNECT_TIMEOUT,
-                         timeout=FUCHSIA_DEFAULT_COMMAND_TIMEOUT,
-                         skip_status_code_check=False):
-        """Sends an SSH command to a Fuchsia device
-
-        Args:
-            test_cmd: string, command to send to Fuchsia device over SSH.
-            connect_timeout: Timeout to wait for connecting via SSH.
-            timeout: Timeout to wait for a command to complete.
-            skip_status_code_check: Whether to check for the status code.
-
-        Returns:
-            A SshResults object containing the results of the ssh command.
-        """
-        command_result = False
-        ssh_conn = None
-        if not self.ssh_config:
-            self.log.warning(FUCHSIA_SSH_CONFIG_NOT_DEFINED)
-        else:
-            try:
-                ssh_conn = create_ssh_connection(
-                    self.ip,
-                    self.ssh_username,
-                    self.ssh_config,
-                    ssh_port=self.ssh_port,
-                    connect_timeout=connect_timeout)
-                cmd_result_stdin, cmd_result_stdout, cmd_result_stderr = (
-                    ssh_conn.exec_command(test_cmd, timeout=timeout))
-                if not skip_status_code_check:
-                    command_result = SshResults(cmd_result_stdin,
-                                                cmd_result_stdout,
-                                                cmd_result_stderr,
-                                                cmd_result_stdout.channel)
-            except Exception as e:
-                self.log.warning("Problem running ssh command: %s"
-                                 "\n Exception: %s" % (test_cmd, e))
-                return e
-            finally:
-                if ssh_conn is not None:
-                    ssh_conn.close()
-        return command_result
-
-    def version(self, timeout=FUCHSIA_DEFAULT_COMMAND_TIMEOUT):
+    def version(self):
         """Returns the version of Fuchsia running on the device.
 
-        Args:
-            timeout: (int) Seconds to wait for command to run.
-
         Returns:
-            A string containing the Fuchsia version number.
-            For example, "5.20210713.2.1".
+            A string containing the Fuchsia version number or nothing if there
+            is no version information attached during the build.
+            For example, "5.20210713.2.1" or "".
 
         Raises:
-            DeviceOffline: If SSH to the device fails.
+            FFXTimeout: when the command times out.
+            FFXError: when the command returns non-zero and skip_status_code_check is False.
         """
-        return self.send_command_ssh(FUCHSIA_GET_VERSION_CMD,
-                                     timeout=timeout).stdout
+        target_info_json = self.ffx.run("target show --json").stdout
+        target_info = json.loads(target_info_json)
+        build_info = [
+            entry for entry in target_info if entry["label"] == "build"
+        ]
+        if len(build_info) != 1:
+            self.log.warning(
+                f'Expected one entry with label "build", found {build_info}')
+            return ""
+        version_info = [
+            child for child in build_info[0]["child"]
+            if child["label"] == "version"
+        ]
+        if len(version_info) != 1:
+            self.log.warning(
+                f'Expected one entry child with label "version", found {build_info}'
+            )
+            return ""
+        return version_info[0]["value"]
 
     def ping(self,
              dest_ip,
@@ -880,11 +671,13 @@
         self.log.debug("Pinging %s..." % dest_ip)
         if not additional_ping_params:
             additional_ping_params = ''
-        ping_result = self.send_command_ssh(
-            'ping -c %s -i %s -t %s -s %s %s %s' %
-            (count, interval, timeout, size, additional_ping_params, dest_ip))
-        if isinstance(ping_result, job.Error):
-            ping_result = ping_result.result
+
+        try:
+            ping_result = self.ssh.run(
+                f'ping -c {count} -i {interval} -t {timeout} -s {size} '
+                f'{additional_ping_params} {dest_ip}')
+        except FuchsiaSSHError as e:
+            ping_result = e.result
 
         if ping_result.stderr:
             status = False
@@ -921,27 +714,9 @@
                                 additional_ping_params=additional_ping_params)
         return ping_result['status']
 
-    def print_clients(self):
-        """Gets connected clients from SL4F server"""
-        self.log.debug("Request to print clients")
-        print_id = self.build_id(self.test_counter)
-        print_args = {}
-        print_method = "sl4f.sl4f_print_clients"
-        data = json.dumps({
-            "jsonrpc": "2.0",
-            "id": print_id,
-            "method": print_method,
-            "params": print_args
-        })
-
-        r = requests.get(url=self.print_address, data=data).json()
-        self.test_counter += 1
-
-        return r
-
     def clean_up(self):
         """Cleans up the FuchsiaDevice object, releases any resources it
-        claimed, and restores saved networks is applicable. For reboots, use
+        claimed, and restores saved networks if applicable. For reboots, use
         clean_up_services only.
 
         Note: Any exceptions thrown in this method must be caught and handled,
@@ -951,151 +726,113 @@
         # If and only if wlan is configured, and using the policy layer
         if self.association_mechanism == 'policy':
             try:
-                self.wlan_policy_controller._clean_up()
+                self.wlan_policy_controller.clean_up()
             except Exception as err:
                 self.log.warning('Unable to clean up WLAN Policy layer: %s' %
                                  err)
-        try:
-            self.run_commands_from_config(self.teardown_commands)
-        except Exception as err:
-            self.log.warning('Failed to run teardown_commands: %s' % err)
 
-        # This MUST be run, otherwise syslog threads will never join.
-        self.clean_up_services()
+        self.stop_services()
 
-    def clean_up_services(self):
-        """ Cleans up FuchsiaDevice services (e.g. SL4F). Subset of clean_up,
-        to be used for reboots, when testing is to continue (as opposed to
-        teardown after testing is finished.)
-        """
-        cleanup_id = self.build_id(self.test_counter)
-        cleanup_args = {}
-        cleanup_method = "sl4f.sl4f_cleanup"
-        data = json.dumps({
-            "jsonrpc": "2.0",
-            "id": cleanup_id,
-            "method": cleanup_method,
-            "params": cleanup_args
-        })
+        if self.package_server:
+            self.package_server.clean_up()
 
-        try:
-            response = requests.get(
-                url=self.cleanup_address,
-                data=data,
-                timeout=FUCHSIA_DEFAULT_CLEAN_UP_COMMAND_TIMEOUT).json()
-            self.log.debug(response)
-        except Exception as err:
-            self.log.exception("Cleanup request failed with %s:" % err)
-        finally:
-            self.test_counter += 1
-            self.stop_services()
+    def get_interface_ip_addresses(self, interface):
+        return get_interface_ip_addresses(self, interface)
 
-    def check_process_state(self, process_name):
-        """Checks the state of a process on the Fuchsia device
-
-        Returns:
-            True if the process_name is running
-            False if process_name is not running
-        """
-        ps_cmd = self.send_command_ssh("ps")
-        return process_name in ps_cmd.stdout
-
-    def check_process_with_expectation(self, process_name, expectation=None):
-        """Checks the state of a process on the Fuchsia device and returns
-        true or false depending the stated expectation
+    def wait_for_ipv4_addr(self, interface: str) -> None:
+        """Checks if device has an ipv4 private address. Sleeps 1 second between
+        retries.
 
         Args:
-            process_name: The name of the process to check for.
-            expectation: The state expectation of state of process
-        Returns:
-            True if the state of the process matches the expectation
-            False if the state of the process does not match the expectation
-        """
-        process_state = self.check_process_state(process_name)
-        if expectation in DAEMON_ACTIVATED_STATES:
-            return process_state
-        elif expectation in DAEMON_DEACTIVATED_STATES:
-            return not process_state
-        else:
-            raise ValueError("Invalid expectation value (%s). abort!" %
-                             expectation)
+            interface: name of interface from which to get ipv4 address.
 
-    def control_daemon(self, process_name, action):
-        """Starts or stops a process on a Fuchsia device
-
-        Args:
-            process_name: the name of the process to start or stop
-            action: specify whether to start or stop a process
+        Raises:
+            ConnectionError, if device does not have an ipv4 address after all
+            timeout.
         """
-        if not (process_name[-4:] == '.cmx' or process_name[-4:] == '.cml'):
-            process_name = '%s.cmx' % process_name
-        unable_to_connect_msg = None
-        process_state = False
-        try:
-            if not self._persistent_ssh_conn:
-                self._persistent_ssh_conn = (create_ssh_connection(
-                    self.ip,
-                    self.ssh_username,
-                    self.ssh_config,
-                    ssh_port=self.ssh_port))
-            self._persistent_ssh_conn.exec_command(
-                "killall %s" % process_name, timeout=CHANNEL_OPEN_TIMEOUT)
-            # This command will effectively stop the process but should
-            # be used as a cleanup before starting a process.  It is a bit
-            # confusing to have the msg saying "attempting to stop
-            # the process" after the command already tried but since both start
-            # and stop need to run this command, this is the best place
-            # for the command.
-            if action in DAEMON_ACTIVATED_STATES:
-                self.log.debug("Attempting to start Fuchsia "
-                               "devices services.")
-                self._persistent_ssh_conn.exec_command(
-                    "run fuchsia-pkg://fuchsia.com/%s#meta/%s &" %
-                    (process_name[:-4], process_name))
-                process_initial_msg = (
-                    "%s has not started yet. Waiting %i second and "
-                    "checking again." %
-                    (process_name, DAEMON_INIT_TIMEOUT_SEC))
-                process_timeout_msg = ("Timed out waiting for %s to start." %
-                                       process_name)
-                unable_to_connect_msg = ("Unable to start %s no Fuchsia "
-                                         "device via SSH. %s may not "
-                                         "be started." %
-                                         (process_name, process_name))
-            elif action in DAEMON_DEACTIVATED_STATES:
-                process_initial_msg = ("%s is running. Waiting %i second and "
-                                       "checking again." %
-                                       (process_name, DAEMON_INIT_TIMEOUT_SEC))
-                process_timeout_msg = ("Timed out waiting trying to kill %s." %
-                                       process_name)
-                unable_to_connect_msg = ("Unable to stop %s on Fuchsia "
-                                         "device via SSH. %s may "
-                                         "still be running." %
-                                         (process_name, process_name))
+        self.log.info(
+            f'Checking for valid ipv4 addr. Retry {IP_ADDRESS_TIMEOUT} seconds.'
+        )
+        timeout = time.time() + IP_ADDRESS_TIMEOUT
+        while time.time() < timeout:
+            ip_addrs = self.get_interface_ip_addresses(interface)
+
+            if len(ip_addrs['ipv4_private']) > 0:
+                self.log.info("Device has an ipv4 address: "
+                              f"{ip_addrs['ipv4_private'][0]}")
+                break
             else:
-                raise FuchsiaDeviceError(FUCHSIA_INVALID_CONTROL_STATE %
-                                         action)
-            timeout_counter = 0
-            while not process_state:
-                self.log.info(process_initial_msg)
-                time.sleep(DAEMON_INIT_TIMEOUT_SEC)
-                timeout_counter += 1
-                process_state = (self.check_process_with_expectation(
-                    process_name, expectation=action))
-                if timeout_counter == (DAEMON_INIT_TIMEOUT_SEC * 3):
-                    self.log.info(process_timeout_msg)
-                    break
-            if not process_state:
-                raise FuchsiaDeviceError(FUCHSIA_COULD_NOT_GET_DESIRED_STATE %
-                                         (action, process_name))
-        except Exception as e:
-            self.log.info(unable_to_connect_msg)
-            raise e
-        finally:
-            if action == 'stop' and (process_name == 'sl4f'
-                                     or process_name == 'sl4f.cmx'):
-                self._persistent_ssh_conn.close()
-                self._persistent_ssh_conn = None
+                self.log.debug(
+                    'Device does not yet have an ipv4 address...retrying in 1 '
+                    'second.')
+                time.sleep(1)
+        else:
+            raise ConnectionError('Device failed to get an ipv4 address.')
+
+    def wait_for_ipv6_addr(self, interface: str) -> None:
+        """Checks if device has an ipv6 private local address. Sleeps 1 second
+        between retries.
+
+        Args:
+            interface: name of interface from which to get ipv6 address.
+
+        Raises:
+            ConnectionError, if device does not have an ipv6 address after all
+            timeout.
+        """
+        self.log.info(
+            f'Checking for valid ipv6 addr. Retry {IP_ADDRESS_TIMEOUT} seconds.'
+        )
+        timeout = time.time() + IP_ADDRESS_TIMEOUT
+        while time.time() < timeout:
+            ip_addrs = self.get_interface_ip_addresses(interface)
+            if len(ip_addrs['ipv6_private_local']) > 0:
+                self.log.info("Device has an ipv6 private local address: "
+                              f"{ip_addrs['ipv6_private_local'][0]}")
+                break
+            else:
+                self.log.debug(
+                    'Device does not yet have an ipv6 address...retrying in 1 '
+                    'second.')
+                time.sleep(1)
+        else:
+            raise ConnectionError('Device failed to get an ipv6 address.')
+
+    def _check_reachable(self,
+                         timeout_sec: int = FUCHSIA_DEFAULT_CONNECT_TIMEOUT
+                         ) -> None:
+        """Checks the reachability of the Fuchsia device."""
+        end_time = time.time() + timeout_sec
+        self.log.info('Verifying device is reachable.')
+        while time.time() < end_time:
+            # TODO (b/249343632): Consolidate ping commands and fix timeout in
+            # utils.can_ping.
+            if utils.can_ping(job, self.ip):
+                self.log.info('Device is reachable.')
+                break
+            else:
+                self.log.debug(
+                    'Device is not reachable. Retrying in 1 second.')
+                time.sleep(1)
+        else:
+            raise ConnectionError('Device is unreachable.')
+
+    def _check_unreachable(self,
+                           timeout_sec: int = FUCHSIA_DEFAULT_CONNECT_TIMEOUT
+                           ) -> None:
+        """Checks the Fuchsia device becomes unreachable."""
+        end_time = time.time() + timeout_sec
+        self.log.info('Verifying device is unreachable.')
+        while (time.time() < end_time):
+            if utils.can_ping(job, self.ip):
+                self.log.debug(
+                    'Device is still reachable. Retrying in 1 second.')
+                time.sleep(1)
+            else:
+                self.log.info('Device is not reachable.')
+                break
+        else:
+            raise ConnectionError('Device failed to become unreachable.')
 
     def check_connect_response(self, connect_response):
         if connect_response.get("error") is None:
@@ -1138,7 +875,7 @@
             # Country code can be None, from ACTS config.
             if desired_country_code:
                 desired_country_code = desired_country_code.upper()
-                response = self.regulatory_region_lib.setRegion(
+                response = self.sl4f.regulatory_region_lib.setRegion(
                     desired_country_code)
                 if response.get('error'):
                     raise FuchsiaDeviceError(
@@ -1146,7 +883,8 @@
                         response['error'])
                 end_time = time.time() + FUCHSIA_COUNTRY_CODE_TIMEOUT
                 while time.time() < end_time:
-                    ascii_cc = self.wlan_lib.wlanGetCountry(0).get('result')
+                    ascii_cc = self.sl4f.wlan_lib.wlanGetCountry(0).get(
+                        'result')
                     # Convert ascii_cc to string, then compare
                     if ascii_cc and (''.join(chr(c) for c in ascii_cc).upper()
                                      == desired_country_code):
@@ -1158,100 +896,31 @@
                 raise FuchsiaDeviceError('Country code never updated to %s' %
                                          desired_country_code)
 
-    @backoff.on_exception(backoff.constant,
-                          (FuchsiaSyslogError, socket.timeout),
-                          interval=1.5,
-                          max_tries=4)
-    def start_services(self):
-        """Starts long running services on the Fuchsia device.
-
-        Starts a syslog streaming process, SL4F server, initializes a connection
-        to the SL4F server, then starts an isolated ffx daemon.
-
-        """
-        self.log.debug("Attempting to start Fuchsia device services on %s." %
-                       self.ip)
-        if self.ssh_config:
-            self.log_process = create_syslog_process(self.serial,
-                                                     self.log_path,
-                                                     self.ip,
-                                                     self.ssh_username,
-                                                     self.ssh_config,
-                                                     ssh_port=self.ssh_port)
-
-            try:
-                self.log_process.start()
-            except FuchsiaSyslogError as e:
-                # Before backing off and retrying, stop the syslog if it
-                # failed to setup correctly, to prevent threading error when
-                # retrying
-                self.log_process.stop()
-                raise
-
-            self.control_daemon("sl4f.cmx", "start")
-            self.init_sl4f_connection()
-
-            out_name = "fuchsia_device_%s_%s.txt" % (self.serial, 'fw_version')
-            full_out_path = os.path.join(self.log_path, out_name)
-            fw_file = open(full_out_path, 'w')
-            fw_file.write('%s\n' % self.version())
-            fw_file.close()
-
-        self.init_ffx_connection()
-
     def stop_services(self):
-        """Stops long running services on the fuchsia device.
-
-        Terminates the syslog streaming process, the SL4F server on the device,
-        and the ffx daemon.
-        """
-        self.log.debug("Attempting to stop Fuchsia device services on %s." %
-                       self.ip)
-        if hasattr(self, 'ffx'):
-            self.ffx.clean_up()
-        if self.ssh_config:
-            try:
-                self.control_daemon("sl4f.cmx", "stop")
-            except Exception as err:
-                self.log.exception("Failed to stop sl4f.cmx with: %s" % err)
-            if self.log_process:
-                self.log_process.stop()
+        """Stops the ffx daemon and deletes SL4F property."""
+        self.log.info('Stopping host device services.')
+        del self.sl4f
+        del self.ffx
 
     def load_config(self, config):
         pass
 
-    def take_bug_report(self,
-                        test_name=None,
-                        begin_time=None,
-                        additional_log_objects=None):
+    def take_bug_report(self, test_name=None, begin_time=None):
         """Takes a bug report on the device and stores it in a file.
 
         Args:
-            test_name: Name of the test case that triggered this bug report.
-            begin_time: Epoch time when the test started. If not specified, the
-                current time will be used.
-            additional_log_objects: A list of additional objects in Fuchsia to
-                query in the bug report.  Must be in the following format:
-                /hub/c/scenic.cmx/[0-9]*/out/objects
+            test_name: DEPRECATED. Do not specify this argument; it is only used
+                for logging. Name of the test case that triggered this bug
+                report.
+            begin_time: DEPRECATED. Do not specify this argument; it allows
+                overwriting of bug reports when this function is called several
+                times in one test. Epoch time when the test started. If not
+                specified, the current time will be used.
         """
-        if not additional_log_objects:
-            additional_log_objects = []
-        log_items = []
-        matching_log_items = FUCHSIA_DEFAULT_LOG_ITEMS
-        for additional_log_object in additional_log_objects:
-            if additional_log_object not in matching_log_items:
-                matching_log_items.append(additional_log_object)
-        sn_path = context.get_current_context().get_full_output_path()
-        os.makedirs(sn_path, exist_ok=True)
-
-        epoch = begin_time if begin_time else utils.get_current_epoch_time()
-        time_stamp = acts_logger.normalize_log_line_timestamp(
-            acts_logger.epoch_to_log_line_timestamp(epoch))
-        out_name = f"{self.mdns_name}_{time_stamp}"
-        snapshot_out_name = f"{out_name}.zip"
-        out_name = "%s.txt" % out_name
-        full_out_path = os.path.join(sn_path, out_name)
-        full_sn_out_path = os.path.join(sn_path, snapshot_out_name)
+        if not self.ssh_config:
+            self.log.warn(
+                'Skipping take_bug_report because ssh_config is not specified')
+            return
 
         if test_name:
             self.log.info(
@@ -1259,30 +928,19 @@
         else:
             self.log.info(f"Taking snapshot of {self.mdns_name}")
 
-        if self.ssh_config is not None:
-            try:
-                subprocess.run([
-                    f"ssh -F {self.ssh_config} {self.ip} snapshot > {full_sn_out_path}"
-                ],
-                               shell=True)
-                self.log.info("Snapshot saved at: {}".format(full_sn_out_path))
-            except Exception as err:
-                self.log.error("Failed to take snapshot with: {}".format(err))
+        epoch = begin_time if begin_time else utils.get_current_epoch_time()
+        time_stamp = acts_logger.normalize_log_line_timestamp(
+            acts_logger.epoch_to_log_line_timestamp(epoch))
+        out_dir = context.get_current_context().get_full_output_path()
+        out_path = os.path.join(out_dir, f'{self.mdns_name}_{time_stamp}.zip')
 
-        system_objects = self.send_command_ssh('iquery --find /hub').stdout
-        system_objects = system_objects.split()
-
-        for matching_log_item in matching_log_items:
-            for system_object in system_objects:
-                if re.match(matching_log_item, system_object):
-                    log_items.append(system_object)
-
-        log_command = '%s %s' % (FUCHSIA_DEFAULT_LOG_CMD, ' '.join(log_items))
-        bug_report_data = self.send_command_ssh(log_command).stdout
-
-        bug_report_file = open(full_out_path, 'w')
-        bug_report_file.write(bug_report_data)
-        bug_report_file.close()
+        try:
+            subprocess.run(
+                [f"ssh -F {self.ssh_config} {self.ip} snapshot > {out_path}"],
+                shell=True)
+            self.log.info(f'Snapshot saved to {out_path}')
+        except Exception as err:
+            self.log.error(f'Failed to take snapshot: {err}')
 
     def take_bt_snoop_log(self, custom_name=None):
         """Takes a the bt-snoop log from the device and stores it in a file
@@ -1299,14 +957,7 @@
         else:
             out_name = "%s.pcap" % out_name
         full_out_path = os.path.join(bt_snoop_path, out_name)
-        bt_snoop_data = self.send_command_ssh(
-            'bt-snoop-cli -d -f pcap').raw_stdout
+        bt_snoop_data = self.ssh.run('bt-snoop-cli -d -f pcap').raw_stdout
         bt_snoop_file = open(full_out_path, 'wb')
         bt_snoop_file.write(bt_snoop_data)
         bt_snoop_file.close()
-
-
-class FuchsiaDeviceLoggerAdapter(logging.LoggerAdapter):
-    def process(self, msg, kwargs):
-        msg = "[FuchsiaDevice|%s] %s" % (self.extra["ip"], msg)
-        return msg, kwargs
diff --git a/acts/framework/acts/controllers/fuchsia_lib/audio_lib.py b/acts/framework/acts/controllers/fuchsia_lib/audio_lib.py
index 753f4a2..748f3cd 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/audio_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/audio_lib.py
@@ -21,11 +21,9 @@
 
 
 class FuchsiaAudioLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-        self.log = logger.create_tagged_trace_logger('FuchsiaAudioLib')
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "audio")
 
     def startOutputSave(self):
         """Starts saving audio output on the device
@@ -35,10 +33,8 @@
         """
         test_cmd = "audio_facade.StartOutputSave"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def stopOutputSave(self):
         """Stops saving audio output on the device
@@ -48,10 +44,8 @@
         """
         test_cmd = "audio_facade.StopOutputSave"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getOutputAudio(self, save_path):
         """Gets the saved audio in base64 encoding. Use base64.b64decode.
@@ -64,10 +58,8 @@
         """
         test_cmd = "audio_facade.GetOutputAudio"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        result = self.send_command(test_id, test_cmd, test_args)
+        result = self.send_command(test_cmd, test_args)
         if result.get("error") is not None:
             self.log.error("Failed to get recorded audio.")
             return False
diff --git a/acts/framework/acts/controllers/fuchsia_lib/backlight_lib.py b/acts/framework/acts/controllers/fuchsia_lib/backlight_lib.py
deleted file mode 100644
index b2ba2bc..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/backlight_lib.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-import datetime
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaBacklightLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def getStateNormalized(self):
-        """Gets the backlight state and normalized brightness.
-
-        Returns:
-          The backlight state as a bool and the normalized brightness as a float in [0.0, 1.0], or
-          an error if the call failed.
-        """
-        test_cmd = 'backlight_facade.GetStateNormalized'
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setStateNormalized(self, backlight_on, brightness):
-        """Sets the backlight state and normalized brightness.
-
-        Args:
-          backlight_on: A bool indicating whether or not the backlight is on.
-          brightness: A float in [0.0, 1.0] representing the backlight brightness.
-
-        Returns:
-          None or an error if the call failed.
-        """
-        test_cmd = 'backlight_facade.SetStateNormalized'
-        test_args = {'backlight_on': backlight_on, 'brightness': brightness}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getNormalizedBrightnessScale(self):
-        """Gets the normalized brightness scale.
-
-        Returns:
-          The normalized brightness scale as a float in [0.0, 1.0], or an error if the call failed.
-        """
-        test_cmd = 'backlight_facade.GetNormalizedBrightnessScale'
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setNormalizedBrightnessScale(self, scale):
-        """Sets the normalized brightness scale.
-
-        Args:
-          scale: The normalized brightness scale to set as a float in [0.0, 1.0].
-
-        Returns:
-          None or an error if the call failed.
-        """
-        test_cmd = 'backlight_facade.SetNormalizedBrightnessScale'
-        test_args = scale
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/base_lib.py b/acts/framework/acts/controllers/fuchsia_lib/base_lib.py
index 23035fc..d282106 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/base_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/base_lib.py
@@ -14,74 +14,94 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import collections
 import json
-import logging
-import math
-import os
-import random
-import re
-import requests
 import socket
-import time
 
+from typing import Any, Mapping
 from urllib.parse import urlparse
+from urllib.request import Request, urlopen
 
-from acts import utils
+from acts import logger, utils
 from acts.libs.proc import job
 
+DEFAULT_SL4F_RESPONSE_TIMEOUT_SEC = 30
+
 
 class DeviceOffline(Exception):
     """Exception if the device is no longer reachable via the network."""
 
 
+class SL4FCommandFailed(Exception):
+    """A SL4F command to the server failed."""
+
+
 class BaseLib():
-    def __init__(self, addr, tc, client_id):
+
+    def __init__(self, addr: str, logger_tag: str) -> None:
         self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+        self.log = logger.create_tagged_trace_logger(f"SL4F | {self.address} | {logger_tag}")
 
-    def build_id(self, test_id):
-        """Concatenates client_id and test_id to form a command_id.
-
-        Args:
-            test_id: string, unique identifier of test command.
-        """
-        return self.client_id + "." + str(test_id)
-
-    def send_command(self, test_id, test_cmd, test_args, response_timeout=30):
+    def send_command(
+        self,
+        cmd: str,
+        args: Mapping[str, Any],
+        response_timeout: int = DEFAULT_SL4F_RESPONSE_TIMEOUT_SEC
+    ) -> Mapping[str, Any]:
         """Builds and sends a JSON command to SL4F server.
 
         Args:
-            test_id: string, unique identifier of test command.
-            test_cmd: string, sl4f method name of command.
-            test_args: dictionary, arguments required to execute test_cmd.
-            response_timeout: int, seconds to wait for a response before
-                throwing an exception. Defaults to no timeout.
+            cmd: SL4F method name of command.
+            args: Arguments required to execute cmd.
+            response_timeout: Seconds to wait for a response before
+                throwing an exception.
 
         Returns:
-            Dictionary, Result of sl4f command executed.
+            Response from SL4F server.
+
+        Throws:
+            TimeoutError: The HTTP request timed out waiting for a response
         """
-        if not utils.can_ping(job, urlparse(self.address).hostname):
-            raise DeviceOffline("FuchsiaDevice %s is not reachable via the "
-                                "network." % urlparse(self.address).hostname)
-        test_data = json.dumps({
+        data = {
             "jsonrpc": "2.0",
-            "id": test_id,
-            "method": test_cmd,
-            "params": test_args
-        })
+            # id is required by the SL4F server to parse test_data but is not
+            # currently used.
+            "id": "",
+            "method": cmd,
+            "params": args
+        }
+        data_json = json.dumps(data).encode("utf-8")
+        req = Request(self.address,
+                      data=data_json,
+                      headers={
+                          "Content-Type": "application/json; charset=utf-8",
+                          "Content-Length": len(data_json),
+                      })
+
+        self.log.debug(f'Sending request "{cmd}" with {args}')
         try:
-            return requests.get(url=self.address,
-                                data=test_data,
-                                timeout=response_timeout).json()
-        except requests.exceptions.Timeout as e:
-            if not utils.can_ping(job, urlparse(self.address).hostname):
+            response = urlopen(req, timeout=response_timeout)
+        except (TimeoutError, socket.timeout) as e:
+            host = urlparse(self.address).hostname
+            if not utils.can_ping(job, host):
                 raise DeviceOffline(
-                    "FuchsiaDevice %s is not reachable via the "
-                    "network." % urlparse(self.address).hostname)
-            else:
-                logging.debug(
-                    'FuchsiaDevice %s is online but SL4f call timed out.' %
-                    urlparse(self.address).hostname)
-                raise e
+                    f'FuchsiaDevice {host} is not reachable via the network.')
+            if type(e) == socket.timeout:
+                # socket.timeout was aliased to TimeoutError in Python 3.10. For
+                # older versions of Python, we need to cast to TimeoutError to
+                # provide a version-agnostic API.
+                raise TimeoutError("socket timeout") from e
+            raise e
+
+        response_body = response.read().decode("utf-8")
+        try:
+            response_json = json.loads(response_body)
+            self.log.debug(f'Received response for "{cmd}": {response_json}')
+        except json.JSONDecodeError as e:
+            raise SL4FCommandFailed(response_body) from e
+
+        # If the SL4F command fails it returns a str, without an 'error' field
+        # to get.
+        if not isinstance(response_json, dict):
+            raise SL4FCommandFailed(response_json)
+
+        return response_json
diff --git a/acts/framework/acts/controllers/fuchsia_lib/basemgr_lib.py b/acts/framework/acts/controllers/fuchsia_lib/basemgr_lib.py
index 6772d38..9e9f037 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/basemgr_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/basemgr_lib.py
@@ -22,10 +22,9 @@
 
 
 class FuchsiaBasemgrLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "basemgr")
 
     def restartSession(self):
         """Restarts an ongoing basemgr session
@@ -36,10 +35,8 @@
                 result: 'Success', 'NoSessionToRestart', or None if error
         """
         test_cmd = COMMAND_RESTART_SESSION
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, {})
+        return self.send_command(test_cmd, {})
 
     def startBasemgr(self):
         """Starts basemgr service
@@ -50,10 +47,8 @@
                 result: 'Success' or None if error
         """
         test_cmd = COMMAND_START_BASEMGR
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, {})
+        return self.send_command(test_cmd, {})
 
     def killBasemgr(self):
         """Kill basemgr service, if one is running
@@ -64,7 +59,5 @@
                 result: 'Success', 'NoBasemgrToKill', or None if error
         """
         test_cmd = COMMAND_KILL_BASEMGR
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, {})
+        return self.send_command(test_cmd, {})
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/avdtp_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/avdtp_lib.py
index fc2a549..e1110f5 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/avdtp_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/avdtp_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaAvdtpLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "avdtp")
 
     def init(self, initiator_delay=None):
         """Initializes the AVDTP service with optional initiator_delay.
@@ -34,12 +33,9 @@
             Dictionary, None if success, error if error.
         """
         test_cmd = "avdtp_facade.AvdtpInit"
-
         test_args = {"initiator_delay": initiator_delay}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getConnectedPeers(self):
         """Gets the AVDTP connected peers.
@@ -49,10 +45,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpGetConnectedPeers"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setConfiguration(self, peer_id):
         """Sends the AVDTP command to input peer_id: set configuration
@@ -65,10 +59,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpSetConfiguration"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getConfiguration(self, peer_id):
         """Sends the AVDTP command to input peer_id: get configuration
@@ -81,10 +73,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpGetConfiguration"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getCapabilities(self, peer_id):
         """Sends the AVDTP command to input peer_id: get capabilities
@@ -97,10 +87,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpGetCapabilities"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getAllCapabilities(self, peer_id):
         """Sends the AVDTP command to input peer_id: get all capabilities
@@ -113,10 +101,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpGetAllCapabilities"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def reconfigureStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: reconfigure stream
@@ -129,10 +115,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpReconfigureStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def suspendStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: suspend stream
@@ -144,10 +128,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpSuspendStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def suspendAndReconfigure(self, peer_id):
         """Sends the AVDTP command to input peer_id: suspend and reconfigure
@@ -160,10 +142,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpSuspendAndReconfigure"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def releaseStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: release stream
@@ -176,10 +156,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpReleaseStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def establishStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: establish stream
@@ -192,10 +170,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpEstablishStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def startStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: start stream
@@ -208,10 +184,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpStartStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def abortStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: abort stream
@@ -227,7 +201,7 @@
         test_id = self.build_id(self.test_counter)
         self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def establishStream(self, peer_id):
         """Sends the AVDTP command to input peer_id: establish stream
@@ -240,10 +214,8 @@
         """
         test_cmd = "avdtp_facade.AvdtpEstablishStream"
         test_args = {"identifier": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def removeService(self):
         """Removes the AVDTP service from the Fuchsia device
@@ -253,7 +225,5 @@
         """
         test_cmd = "avdtp_facade.AvdtpRemoveService"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/ble_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/ble_lib.py
index 7a46e07..acf1564 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/ble_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/ble_lib.py
@@ -20,10 +20,9 @@
 
 
 class FuchsiaBleLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "ble")
 
     def _convert_human_readable_uuid_to_byte_list(self, readable_uuid):
         """Converts a readable uuid to a byte list.
@@ -31,7 +30,8 @@
         Args:
             readable_uuid: string, A readable uuid in the format:
                 Input: "00001101-0000-1000-8000-00805f9b34fb"
-                Output: ['fb', '34', '9b', '5f', '80', '00', '00', '80', '00', '10', '00', '00', '01', '11', '00', '00']
+                Output: ['fb', '34', '9b', '5f', '80', '00', '00', '80', '00',
+                         '10', '00', '00', '01', '11', '00', '00']
 
         Returns:
             A byte list representing the readable uuid.
@@ -53,10 +53,8 @@
         """
         test_cmd = "ble_advertise_facade.BleStopAdvertise"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def bleStartBleAdvertising(self,
                                advertising_data,
@@ -112,15 +110,12 @@
             "interval_ms": interval,
             "connectable": connectable
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
-    def blePublishService(self, id_, primary, type_, service_id):
+    def blePublishService(self, primary, type_, service_id):
         """Publishes services specified by input args
 
         Args:
-            id: string, Identifier of service.
             primary: bool, Flag of service.
             type: string, Canonical 8-4-4-4-12 uuid of service.
             service_proxy_key: string, Unique identifier to specify where to publish service
@@ -130,12 +125,9 @@
         """
         test_cmd = "bluetooth.BlePublishService"
         test_args = {
-            "id": id_,
             "primary": primary,
             "type": type_,
             "local_service_id": service_id
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/bts_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/bts_lib.py
index 9d4203d..bbb3823 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/bts_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/bts_lib.py
@@ -14,27 +14,14 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import collections
-import json
-import logging
-import math
-import os
-import random
-import re
-import requests
-import socket
-import time
-
 from acts.controllers.fuchsia_lib.base_lib import BaseLib
 
 
 class FuchsiaBtsLib(BaseLib):
     # Class representing the Bluetooth Access Library.
 
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "bt_sys")
 
     def setDiscoverable(self, discoverable):
         """Sets the device to be discoverable over BR/EDR.
@@ -48,10 +35,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothSetDiscoverable"
         test_args = {"discoverable": discoverable}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setName(self, name):
         """Sets the local Bluetooth name of the device.
@@ -64,10 +49,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothSetName"
         test_args = {"name": name}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def inputPairingPin(self, pin):
         """Inputs the pairing pin to the Fuchsia devices' pairing delegate.
@@ -80,10 +63,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothInputPairingPin"
         test_args = {"pin": pin}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getPairingPin(self):
         """Gets the pairing pin from the Fuchsia devices' pairing delegate.
@@ -93,10 +74,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothGetPairingPin"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def initBluetoothSys(self):
         """Initialises the Bluetooth sys Interface proxy in SL4F.
@@ -106,10 +85,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothInitSys"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def requestDiscovery(self, discovery):
         """Start or stop Bluetooth Control device discovery.
@@ -123,10 +100,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothRequestDiscovery"
         test_args = {"discovery": discovery}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getKnownRemoteDevices(self):
         """Get known remote BR/EDR and LE devices.
@@ -136,10 +111,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothGetKnownRemoteDevices"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def forgetDevice(self, identifier):
         """Forgets a devices pairing.
@@ -152,10 +125,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothForgetDevice"
         test_args = {"identifier": identifier}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def disconnectDevice(self, identifier):
         """Disconnects a devices.
@@ -168,10 +139,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothDisconnectDevice"
         test_args = {"identifier": identifier}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def connectDevice(self, identifier):
         """Connects to a devices.
@@ -184,10 +153,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothConnectDevice"
         test_args = {"identifier": identifier}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getActiveAdapterAddress(self):
         """Gets the current Active Adapter's address.
@@ -197,10 +164,8 @@
         """
         test_cmd = "bt_sys_facade.BluetoothGetActiveAdapterAddress"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def pair(self, identifier, pairing_security_level, non_bondable,
              transport):
@@ -231,9 +196,8 @@
             "non_bondable": non_bondable,
             "transport": transport,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        return self.send_command(test_id, test_cmd, test_args)
+
+        return self.send_command(test_cmd, test_args)
 
     def acceptPairing(self,
                       input_capabilities="NONE",
@@ -259,6 +223,5 @@
             "input": input_capabilities,
             "output": output_capabilities,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        return self.send_command(test_id, test_cmd, test_args)
+
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/gattc_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/gattc_lib.py
index b64ed4d..e9e3f5c 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/gattc_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/gattc_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaGattcLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "gatt_client")
 
     def bleStartBleScan(self, scan_filter):
         """Starts a BLE scan
@@ -38,10 +37,8 @@
         test_args = {
             "filter": scan_filter,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def bleStopBleScan(self):
         """Stops a BLE scan
@@ -51,10 +48,8 @@
         """
         test_cmd = "gatt_client_facade.BleStopScan"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def listServices(self, id):
         """Lists services of a peripheral specified by id.
@@ -67,10 +62,8 @@
         """
         test_cmd = "gatt_client_facade.GattcListServices"
         test_args = {"identifier": id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def bleGetDiscoveredDevices(self):
         """Stops a BLE scan
@@ -80,10 +73,8 @@
         """
         test_cmd = "gatt_client_facade.BleGetDiscoveredDevices"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def discoverCharacteristics(self):
         """Discover the characteristics of a connected service.
@@ -94,10 +85,8 @@
         """
         test_cmd = "gatt_client_facade.GattcDiscoverCharacteristics"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeCharById(self, id, offset, write_value):
         """Write Characteristic by id..
@@ -116,10 +105,8 @@
             "offset": offset,
             "write_value": write_value,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeLongCharById(self, id, offset, write_value, reliable_mode=False):
         """Write Characteristic by id.
@@ -140,10 +127,8 @@
             "write_value": write_value,
             "reliable_mode": reliable_mode
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeLongDescById(self, id, offset, write_value):
         """Write Descriptor by id.
@@ -162,10 +147,8 @@
             "offset": offset,
             "write_value": write_value,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeCharByIdWithoutResponse(self, id, write_value):
         """Write Characteristic by id without response.
@@ -182,10 +165,8 @@
             "identifier": id,
             "write_value": write_value,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def enableNotifyCharacteristic(self, id):
         """Enable notifications on a Characteristic.
@@ -200,10 +181,8 @@
         test_args = {
             "identifier": id,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def disableNotifyCharacteristic(self, id):
         """Disable notifications on a Characteristic.
@@ -219,10 +198,8 @@
             "identifier": id,
             "value": False,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def readCharacteristicById(self, id):
         """Read Characteristic value by id..
@@ -237,10 +214,8 @@
         test_args = {
             "identifier": id,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def readCharacteristicByType(self, uuid):
         """Read Characteristic value by id..
@@ -255,10 +230,8 @@
         test_args = {
             "uuid": uuid,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def readDescriptorById(self, id):
         """Read Descriptor value by id..
@@ -273,10 +246,8 @@
         test_args = {
             "identifier": id,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def readLongDescriptorById(self, id, offset, max_bytes):
         """Reads Long Descriptor value by id.
@@ -295,10 +266,8 @@
             "offset": offset,
             "max_bytes": max_bytes
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeDescriptorById(self, id, offset, write_value):
         """Write Descriptor by id.
@@ -315,10 +284,8 @@
             "identifier": id,
             "write_value": write_value,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def readLongCharacteristicById(self, id, offset, max_bytes):
         """Reads Long Characteristic value by id.
@@ -337,10 +304,8 @@
             "offset": offset,
             "max_bytes": max_bytes
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def connectToService(self, id, service_id):
         """ Connect to a specific Service specified by id.
@@ -353,10 +318,8 @@
         """
         test_cmd = "gatt_client_facade.GattcConnectToService"
         test_args = {"identifier": id, "service_identifier": service_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def bleConnectToPeripheral(self, id):
         """Connects to a peripheral specified by id.
@@ -369,10 +332,8 @@
         """
         test_cmd = "gatt_client_facade.BleConnectPeripheral"
         test_args = {"identifier": id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def bleDisconnectPeripheral(self, id):
         """Disconnects from a peripheral specified by id.
@@ -385,7 +346,5 @@
         """
         test_cmd = "gatt_client_facade.BleDisconnectPeripheral"
         test_args = {"identifier": id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
\ No newline at end of file
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/gatts_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/gatts_lib.py
index 74dc770..23a983e 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/gatts_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/gatts_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaGattsLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "gatt_server")
 
     def publishServer(self, database):
         """Publishes services specified by input args
@@ -37,10 +36,8 @@
         test_args = {
             "database": database,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def closeServer(self):
         """Closes an active GATT server.
@@ -50,7 +47,5 @@
         """
         test_cmd = "gatt_server_facade.GattServerCloseServer"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
index cd789cf..af51db1 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaHfpLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "hfp")
 
     def init(self):
         """Initializes the HFP service.
@@ -30,12 +29,9 @@
             Dictionary, None if success, error if error.
         """
         test_cmd = "hfp_facade.HfpInit"
-
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def removeService(self):
         """Removes the HFP service from the Fuchsia device
@@ -45,10 +41,8 @@
         """
         test_cmd = "hfp_facade.HfpRemoveService"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def listPeers(self):
         """List all connected HFP peer devices.
@@ -58,10 +52,8 @@
         """
         test_cmd = "hfp_facade.ListPeers"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setActivePeer(self, peer_id):
         """Set the active HFP peer device. All peer specific commands will be
@@ -76,10 +68,8 @@
         """
         test_cmd = "hfp_facade.SetActivePeer"
         test_args = {"peer_id": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def listCalls(self):
         """List all calls known to the sl4f component.
@@ -89,10 +79,8 @@
         """
         test_cmd = "hfp_facade.ListCalls"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def newCall(self, remote, state, direction):
         """Opens a new call channel and alerts the HFP peer.
@@ -107,10 +95,8 @@
         """
         test_cmd = "hfp_facade.NewCall"
         test_args = {"remote": remote, "state": state, "direction": direction}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def initiateIncomingCall(self, remote):
         """Opens an incoming call channel and alerts the HFP peer.
@@ -123,10 +109,8 @@
         """
         test_cmd = "hfp_facade.IncomingCall"
         test_args = {"remote": remote}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def initiateIncomingWaitingCall(self, remote):
         """Opens an incoming call when there is an onging call and alerts
@@ -139,11 +123,9 @@
             Dictionary, call_id if success, error if error.
         """
         test_cmd = "hfp_facade.IncomingWaitingCall"
-        test_args = {"remote": remote }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
+        test_args = {"remote": remote}
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def initiateOutgoingCall(self, remote):
         """Opens an outgoing call channel and alerts the HFP peer.
@@ -156,10 +138,8 @@
         """
         test_cmd = "hfp_facade.OutgoingCall"
         test_args = {"remote": remote}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setCallActive(self, call_id):
         """Sets the specified call to the "OngoingActive" state.
@@ -172,10 +152,8 @@
         """
         test_cmd = "hfp_facade.SetCallActive"
         test_args = {"call_id": call_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setCallHeld(self, call_id):
         """Sets the specified call to the "OngoingHeld" state.
@@ -188,10 +166,8 @@
         """
         test_cmd = "hfp_facade.SetCallHeld"
         test_args = {"call_id": call_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setCallTerminated(self, call_id):
         """Sets the specified call to the "Terminated" state.
@@ -204,10 +180,8 @@
         """
         test_cmd = "hfp_facade.SetCallTerminated"
         test_args = {"call_id": call_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setCallTransferredToAg(self, call_id):
         """Sets the specified call to the "TransferredToAg" state.
@@ -220,10 +194,8 @@
         """
         test_cmd = "hfp_facade.SetCallTransferredToAg"
         test_args = {"call_id": call_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setSpeakerGain(self, value):
         """Sets the active peer's speaker gain.
@@ -236,10 +208,8 @@
         """
         test_cmd = "hfp_facade.SetSpeakerGain"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setMicrophoneGain(self, value):
         """Sets the active peer's microphone gain.
@@ -252,10 +222,8 @@
         """
         test_cmd = "hfp_facade.SetMicrophoneGain"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setServiceAvailable(self, value):
         """Sets the simulated network service status reported by the call manager.
@@ -268,10 +236,8 @@
         """
         test_cmd = "hfp_facade.SetServiceAvailable"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setRoaming(self, value):
         """Sets the simulated roaming status reported by the call manager.
@@ -284,10 +250,8 @@
         """
         test_cmd = "hfp_facade.SetRoaming"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setSignalStrength(self, value):
         """Sets the simulated signal strength reported by the call manager.
@@ -300,10 +264,8 @@
         """
         test_cmd = "hfp_facade.SetSignalStrength"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setSubscriberNumber(self, value):
         """Sets the subscriber number reported by the call manager.
@@ -316,10 +278,8 @@
         """
         test_cmd = "hfp_facade.SetSubscriberNumber"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setOperator(self, value):
         """Sets the operator value reported by the call manager.
@@ -332,10 +292,8 @@
         """
         test_cmd = "hfp_facade.SetOperator"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setNrecSupport(self, value):
         """Sets the noise reduction/echo cancelation support reported by the call manager.
@@ -348,10 +306,8 @@
         """
         test_cmd = "hfp_facade.SetNrecSupport"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setBatteryLevel(self, value):
         """Sets the battery level reported by the call manager.
@@ -364,10 +320,8 @@
         """
         test_cmd = "hfp_facade.SetBatteryLevel"
         test_args = {"value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setLastDialed(self, number):
         """Sets the last dialed number in the call manager.
@@ -380,10 +334,8 @@
         """
         test_cmd = "hfp_facade.SetLastDialed"
         test_args = {"number": number}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def clearLastDialed(self):
         """Clears the last dialed number in the call manager.
@@ -393,10 +345,8 @@
         """
         test_cmd = "hfp_facade.ClearLastDialed"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setMemoryLocation(self, location, number):
         """Sets a memory location to point to a remote number.
@@ -410,10 +360,8 @@
         """
         test_cmd = "hfp_facade.SetMemoryLocation"
         test_args = {"location": location, "number": number}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def clearMemoryLocation(self, location):
         """Clear a memory location so that it no longer points to a remote
@@ -427,10 +375,8 @@
         """
         test_cmd = "hfp_facade.ClearMemoryLocation"
         test_args = {"location": location}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setDialResult(self, number, status):
         """Sets the status result to be returned when the number is dialed.
@@ -445,10 +391,8 @@
         """
         test_cmd = "hfp_facade.SetDialResult"
         test_args = {"number": number, "status": status}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def getState(self):
         """Get the call manager's state.
@@ -458,10 +402,8 @@
         """
         test_cmd = "hfp_facade.GetState"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def setConnectionBehavior(self, autoconnect):
         """Set the Service Level Connection behavior when a new peer connects.
@@ -474,7 +416,5 @@
         """
         test_cmd = "hfp_facade.SetConnectionBehavior"
         test_args = {"autoconnect": autoconnect}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py
index 6cc08b8..5ed9e96 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaRfcommLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "rfcomm")
 
     def init(self):
         """Initializes the RFCOMM service.
@@ -30,12 +29,9 @@
             Dictionary, None if success, error if error.
         """
         test_cmd = "rfcomm_facade.RfcommInit"
-
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def removeService(self):
         """Removes the RFCOMM service from the Fuchsia device
@@ -45,10 +41,8 @@
         """
         test_cmd = "rfcomm_facade.RfcommRemoveService"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def disconnectSession(self, peer_id):
         """Closes the RFCOMM Session with the remote peer
@@ -58,10 +52,8 @@
         """
         test_cmd = "rfcomm_facade.DisconnectSession"
         test_args = {"peer_id": peer_id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def connectRfcommChannel(self, peer_id, server_channel_number):
         """Makes an outgoing RFCOMM connection to the remote peer
@@ -74,10 +66,8 @@
             "peer_id": peer_id,
             "server_channel_number": server_channel_number
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def disconnectRfcommChannel(self, peer_id, server_channel_number):
         """Closes the RFCOMM channel with the remote peer
@@ -90,10 +80,8 @@
             "peer_id": peer_id,
             "server_channel_number": server_channel_number
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def sendRemoteLineStatus(self, peer_id, server_channel_number):
         """Sends a Remote Line Status update to the remote peer for the provided channel number
@@ -106,10 +94,8 @@
             "peer_id": peer_id,
             "server_channel_number": server_channel_number
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def writeRfcomm(self, peer_id, server_channel_number, data):
         """Sends data to the remote peer over the RFCOMM channel
@@ -123,7 +109,5 @@
             "server_channel_number": server_channel_number,
             "data": data
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/sdp_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/sdp_lib.py
index 6f7a62c..f050283 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/sdp_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/sdp_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaProfileServerLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "profile_server")
 
     def addService(self, record):
         """Publishes an SDP service record specified by input args
@@ -37,10 +36,8 @@
         test_args = {
             "record": record,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def addSearch(self, attribute_list, profile_id):
         """Publishes services specified by input args
@@ -56,10 +53,8 @@
             "attribute_list": attribute_list,
             "profile_id": profile_id
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def removeService(self, service_id):
         """Removes a service.
@@ -75,10 +70,8 @@
         test_args = {
             "service_id": service_id,
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def init(self):
         """Initializes the ProfileServerFacade's proxy object.
@@ -90,10 +83,8 @@
         """
         test_cmd = "profile_server_facade.ProfileServerInit"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def cleanUp(self):
         """Cleans up all objects related to SDP.
@@ -103,10 +94,8 @@
         """
         test_cmd = "profile_server_facade.ProfileServerCleanup"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def connectL2cap(self, identifier, psm, mode):
         """ Sends an outgoing l2cap connection to a connected peer device.
@@ -143,7 +132,5 @@
         """
         test_cmd = "profile_server_facade.ProfileServerConnectL2cap"
         test_args = {"identifier": identifier, "psm": psm, "mode": mode}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/ffx.py b/acts/framework/acts/controllers/fuchsia_lib/ffx.py
index e407141..1746ff8 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/ffx.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/ffx.py
@@ -17,20 +17,37 @@
 import json
 import os
 import tempfile
+import subprocess
+import time
 
 from pathlib import Path
+from typing import Any, MutableMapping, Optional
 
 from acts import context
 from acts import logger
 from acts import signals
 from acts import utils
-from acts.libs.proc import job
 
-FFX_DEFAULT_COMMAND_TIMEOUT = 60
+
+FFX_DEFAULT_COMMAND_TIMEOUT: int = 60
 
 
 class FFXError(signals.TestError):
-    pass
+    """Non-zero error code returned from a ffx command."""
+
+    def __init__(self, command: str,
+                 process: subprocess.CalledProcessError) -> None:
+        self.command = command
+        self.stdout: str = process.stdout.decode('utf-8', errors='replace')
+        self.stderr: str = process.stderr.decode('utf-8', errors='replace')
+        self.exit_status = process.returncode
+
+    def __str__(self) -> str:
+        return f'ffx subcommand "{self.command}" returned {self.exit_status}, stdout: "{self.stdout}", stderr: "{self.stderr}"'
+
+
+class FFXTimeout(signals.TestError):
+    """Timed out running a ffx command."""
 
 
 class FFX:
@@ -39,11 +56,16 @@
     Attributes:
         log: Logger for the device-specific instance of ffx.
         binary_path: Path to the ffx binary.
-        target: mDNS nodename of the default Fuchsia target.
+        mdns_name: mDNS nodename of the default Fuchsia target.
+        ip: IP address of the default Fuchsia target.
         ssh_private_key_path: Path to Fuchsia DUT SSH private key.
     """
 
-    def __init__(self, binary_path, target, ssh_private_key_path=None):
+    def __init__(self,
+                 binary_path: str,
+                 mdns_name: str,
+                 ip: str = None,
+                 ssh_private_key_path: str = None):
         """
         Args:
             binary_path: Path to ffx binary.
@@ -51,18 +73,79 @@
             ssh_private_key_path: Path to SSH private key for talking to the
                 Fuchsia DUT.
         """
-        self.log = logger.create_tagged_trace_logger(f"ffx | {target}")
+        self.log = logger.create_tagged_trace_logger(f"ffx | {mdns_name}")
         self.binary_path = binary_path
-        self.target = target
+        self.mdns_name = mdns_name
+        self.ip = ip
         self.ssh_private_key_path = ssh_private_key_path
 
-        self._config_path = None
+        self._env_config_path: Optional[str] = None
+        self._ssh_auth_sock_path: Optional[str] = None
+        self._overnet_socket_path: Optional[str] = None
+        self._has_been_reachable = False
+        self._has_logged_version = False
+
+    def clean_up(self) -> None:
+        if self._env_config_path:
+            self.run("daemon stop", skip_reachability_check=True)
+        if self._ssh_auth_sock_path:
+            Path(self._ssh_auth_sock_path).unlink(missing_ok=True)
+        if self._overnet_socket_path:
+            Path(self._overnet_socket_path).unlink(missing_ok=True)
+
+        self._env_config_path = None
         self._ssh_auth_sock_path = None
         self._overnet_socket_path = None
         self._has_been_reachable = False
         self._has_logged_version = False
 
-    def _create_isolated_environment(self):
+    def run(self,
+            command: str,
+            timeout_sec: int = FFX_DEFAULT_COMMAND_TIMEOUT,
+            skip_status_code_check: bool = False,
+            skip_reachability_check: bool = False
+            ) -> subprocess.CompletedProcess:
+        """Runs an ffx command.
+
+        Verifies reachability before running, if it hasn't already.
+
+        Args:
+            command: Command to run with ffx.
+            timeout_sec: Seconds to wait for a command to complete.
+            skip_status_code_check: Whether to check for the status code.
+            verify_reachable: Whether to verify reachability before running.
+
+        Raises:
+            FFXTimeout: when the command times out.
+            FFXError: when the command returns non-zero and skip_status_code_check is False.
+
+        Returns:
+            The results of the command. Note subprocess.CompletedProcess returns
+            stdout and stderr as a byte-array, not a string. Treat these members
+            as such or convert to a string using bytes.decode('utf-8').
+        """
+        if not self._env_config_path:
+            self._create_isolated_environment()
+        if not self._has_been_reachable and not skip_reachability_check:
+            self.log.info(f'Verifying reachability before running "{command}"')
+            self.verify_reachable()
+
+        self.log.debug(f'Running "{command}".')
+        full_command = f'{self.binary_path} -e {self._env_config_path} {command}'
+
+        try:
+            result = subprocess.run(full_command.split(),
+                                    capture_output=True,
+                                    timeout=timeout_sec,
+                                    check=not skip_status_code_check)
+        except subprocess.CalledProcessError as e:
+            raise FFXError(command, e) from e
+        except subprocess.TimeoutExpired as e:
+            raise FFXTimeout(f'Timed out running "{full_command}"') from e
+
+        return result
+
+    def _create_isolated_environment(self) -> None:
         """ Create a new isolated environment for ffx.
 
         This is needed to avoid overlapping ffx daemons while testing in
@@ -77,7 +160,7 @@
         epoch = utils.get_current_epoch_time()
         time_stamp = logger.normalize_log_line_timestamp(
             logger.epoch_to_log_line_timestamp(epoch))
-        target_dir = os.path.join(root_dir, f'{self.target}_{time_stamp}')
+        target_dir = os.path.join(root_dir, f'{self.mdns_name}_{time_stamp}')
         os.makedirs(target_dir, exist_ok=True)
 
         # Sockets need to be created in a different directory to be guaranteed
@@ -87,9 +170,9 @@
         self._overnet_socket_path = tempfile.mkstemp(
             suffix="overnet_socket")[1]
 
-        config = {
+        config: MutableMapping[str, Any] = {
             "target": {
-                "default": self.target,
+                "default": self.mdns_name,
             },
             # Use user-specific and device-specific locations for sockets.
             # Avoids user permission errors in a multi-user test environment.
@@ -116,19 +199,37 @@
             },
         }
 
+        if self.ip:
+            config["discovery"] = {
+                "mdns": {
+                    "enabled": False,
+                },
+            }
+
         # ffx looks for the private key in several default locations. For
         # testbeds which have the private key in another location, set it now.
         if self.ssh_private_key_path:
             config["ssh"]["priv"] = self.ssh_private_key_path
 
-        self._config_path = os.path.join(target_dir, "ffx_config.json")
-        with open(self._config_path, 'w', encoding="utf-8") as f:
+        config_path = os.path.join(target_dir, "ffx_config.json")
+        with open(config_path, 'w', encoding="utf-8") as f:
             json.dump(config, f, ensure_ascii=False, indent=4)
 
+        env = {
+            "user": config_path,
+            "build": None,
+            "global": None,
+        }
+        self._env_config_path = os.path.join(target_dir, "ffx_env.json")
+        with open(self._env_config_path, 'w', encoding="utf-8") as f:
+            json.dump(env, f, ensure_ascii=False, indent=4)
+
         # The ffx daemon will started automatically when needed. There is no
         # need to start it manually here.
 
-    def verify_reachable(self):
+    def verify_reachable(self,
+                         timeout_sec: int = FFX_DEFAULT_COMMAND_TIMEOUT
+                         ) -> None:
         """Verify the target is reachable via RCS and various services.
 
         Blocks until the device allows for an RCS connection. If the device
@@ -140,20 +241,39 @@
 
         When called for the first time, the versions will be checked for
         compatibility.
+
+        Args:
+            timeout_sec: Seconds to wait for reachability check
+
+        Raises:
+            FFXError: when an unknown error occurs
+            FFXTimeout: when the target is unreachable
         """
-        try:
-            self.run("target wait",
-                     timeout_sec=5,
-                     skip_reachability_check=True)
-        except job.TimeoutError as e:
-            longer_wait_sec = 60
-            self.log.info(
-                "Device is not immediately available via ffx." +
-                f" Waiting up to {longer_wait_sec} seconds for device to be reachable."
-            )
-            self.run("target wait",
-                     timeout_sec=longer_wait_sec,
-                     skip_reachability_check=True)
+        cmd = "target wait"
+        if self.ip:
+            # `target add` does what `target wait` does but adds an entry
+            # to ensure connections can happen without mDNS.
+            # TODO(https://fxbug.dev/105530): Update manual target parsing in
+            # ffx.
+            cmd = f"target add {self.ip}"
+
+        timeout = time.perf_counter() + timeout_sec
+        while True:
+            try:
+                self.run(cmd, timeout_sec=5, skip_reachability_check=True)
+                break
+            except FFXError as e:
+                if 'took too long connecting to ascendd socket' in e.stderr:
+                    err = e
+                else:
+                    raise e
+            except FFXTimeout as e:
+                err = e
+
+            if time.perf_counter() > timeout:
+                raise FFXTimeout(
+                    f'Waited over {timeout_sec}s for ffx to become reachable'
+                ) from err
 
         # Use a shorter timeout than default because device information
         # gathering can hang for a long time if the device is not actually
@@ -174,12 +294,13 @@
             self._has_logged_version = True
             self.compare_version(result)
 
-    def compare_version(self, target_show_result):
+    def compare_version(
+            self, target_show_result: subprocess.CompletedProcess) -> None:
         """Compares the version of Fuchsia with the version of ffx.
 
         Args:
-            target_show_result: job.Result, result of the target show command
-                with JSON output mode enabled
+            target_show_result: Result of the target show command with JSON
+                output mode enabled
         """
         result_json = json.loads(target_show_result.stdout)
         build_info = next(
@@ -187,7 +308,7 @@
         version_info = next(
             filter(lambda s: s.get('label') == 'version', build_info['child']))
         device_version = version_info.get('value')
-        ffx_version = self.run("version").stdout
+        ffx_version = self.run("version").stdout.decode('utf-8')
 
         self.log.info(
             f"Device version: {device_version}, ffx version: {ffx_version}")
@@ -196,67 +317,3 @@
                 "ffx versions that differ from device versions may" +
                 " have compatibility issues. It is recommended to" +
                 " use versions within 6 weeks of each other.")
-
-    def clean_up(self):
-        if self._config_path:
-            self.run("daemon stop", skip_reachability_check=True)
-        if self._ssh_auth_sock_path:
-            Path(self._ssh_auth_sock_path).unlink(missing_ok=True)
-        if self._overnet_socket_path:
-            Path(self._overnet_socket_path).unlink(missing_ok=True)
-
-        self._config_path = None
-        self._ssh_auth_sock_path = None
-        self._overnet_socket_path = None
-        self._has_been_reachable = False
-        self._has_logged_version = False
-
-    def run(self,
-            command,
-            timeout_sec=FFX_DEFAULT_COMMAND_TIMEOUT,
-            skip_status_code_check=False,
-            skip_reachability_check=False):
-        """Runs an ffx command.
-
-        Verifies reachability before running, if it hasn't already.
-
-        Args:
-            command: string, command to run with ffx.
-            timeout_sec: Seconds to wait for a command to complete.
-            skip_status_code_check: Whether to check for the status code.
-            verify_reachable: Whether to verify reachability before running.
-
-        Raises:
-            job.TimeoutError: when the command times out.
-            Error: when the command returns non-zero and skip_status_code_check is False.
-            FFXError: when stderr has contents and skip_status_code_check is False.
-
-        Returns:
-            A job.Result object containing the results of the command.
-        """
-        if not self._config_path:
-            self._create_isolated_environment()
-        if not self._has_been_reachable and not skip_reachability_check:
-            self.log.info(f'Verifying reachability before running "{command}"')
-            self.verify_reachable()
-
-        self.log.debug(f'Running "{command}".')
-
-        full_command = f'{self.binary_path} -c {self._config_path} {command}'
-        result = job.run(command=full_command,
-                         timeout=timeout_sec,
-                         ignore_status=skip_status_code_check)
-
-        if isinstance(result, Exception):
-            raise result
-
-        elif not skip_status_code_check and result.stderr:
-            self.log.warning(
-                f'Ran "{full_command}", exit status {result.exit_status}')
-            self.log.warning(f'stdout: {result.stdout}')
-            self.log.warning(f'stderr: {result.stderr}')
-
-            raise FFXError(
-                f'Error when running "{full_command}": {result.stderr}')
-
-        return result
diff --git a/acts/framework/acts/controllers/fuchsia_lib/gpio_lib.py b/acts/framework/acts/controllers/fuchsia_lib/gpio_lib.py
deleted file mode 100644
index cd4c75d..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/gpio_lib.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaGpioLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def configIn(self, pin, flags):
-        """ Configures a GPIO for input.
-
-        Args:
-           pin: uint32, pin number of GPIO
-           flags: uint32, flags to configure for GPIO
-
-        Returns:
-           None if success, prints error message if error.
-        """
-        test_cmd = "gpio_facade.ConfigIn"
-        test_args = {"pin": pin, "flags": flags}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def configOut(self, pin, value):
-        """ Configures a GPIO for output.
-
-        Args:
-           pin: uint32, pin number of GPIO
-           value: uint8, initial value
-
-        Returns:
-           None if success, prints error message if error.
-        """
-        test_cmd = "gpio_facade.ConfigOut"
-        test_args = {"pin": pin, "value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def read(self, pin):
-        """ Reads the current value of a GPIO (0 or 1).
-
-        Args:
-           pin: uint32, pin number of GPIO
-
-        Returns:
-           uint8. Current value of GPIO.
-        """
-        test_cmd = "gpio_facade.Read"
-        test_args = {"pin": pin}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def write(self, pin, value):
-        """ Sets the current value of the GPIO (any non-zero value maps to 1).
-
-        Args:
-           pin: uint32, pin number of GPIO
-           value: uint8, value of GPIO
-
-        Returns:
-           None if success, prints error message if error.
-        """
-        test_cmd = "gpio_facade.Write"
-        test_args = {"pin": pin, "value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/hardware_power_statecontrol_lib.py b/acts/framework/acts/controllers/fuchsia_lib/hardware_power_statecontrol_lib.py
index 2663a98..d57bf78 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/hardware_power_statecontrol_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/hardware_power_statecontrol_lib.py
@@ -14,9 +14,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import datetime
+import logging
 import http
-import requests
 
 import acts.controllers.fuchsia_lib.base_lib as base_lib
 
@@ -24,10 +23,20 @@
 
 
 class FuchsiaHardwarePowerStatecontrolLib(base_lib.BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "hardware_power_statecontrol")
+
+    def send_command(self, test_cmd, test_args, response_timeout=30):
+        """Wrap send_command to allow disconnects after sending the request."""
+        try:
+            response = super().send_command(test_cmd, test_args,
+                                            response_timeout)
+        except (TimeoutError, http.client.RemoteDisconnected,
+                base_lib.DeviceOffline) as e:
+            logging.warn(f'Error while sending power command: {e}')
+            return
+        return response
 
     def suspendReboot(self, timeout=HW_PWR_STATE_CONTROL_TIMEOUT):
         """Call Suspend Reboot.
@@ -37,18 +46,7 @@
         """
         test_cmd = "hardware_power_statecontrol_facade.SuspendReboot"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        try:
-            response = self.send_command(test_id,
-                                         test_cmd,
-                                         test_args,
-                                         response_timeout=timeout)
-        except (ConnectionResetError, base_lib.DeviceOffline,
-                requests.exceptions.ConnectionError,
-                requests.exceptions.ReadTimeout):
-            return
-        return response
+        return self.send_command(test_cmd, test_args, response_timeout=timeout)
 
     def suspendRebootBootloader(self, timeout=HW_PWR_STATE_CONTROL_TIMEOUT):
         """Call Suspend Reboot Bootloader
@@ -58,17 +56,7 @@
         """
         test_cmd = "hardware_power_statecontrol_facade.SuspendRebootBootloader"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        try:
-            response = self.send_command(test_id,
-                                         test_cmd,
-                                         test_args,
-                                         response_timeout=timeout)
-        except (requests.exceptions.ReadTimeout,
-                http.client.RemoteDisconnected, base_lib.DeviceOffline):
-            return
-        return response
+        return self.send_command(test_cmd, test_args, response_timeout=timeout)
 
     def suspendPoweroff(self, timeout=HW_PWR_STATE_CONTROL_TIMEOUT):
         """Call Suspend Poweroff
@@ -78,17 +66,7 @@
         """
         test_cmd = "hardware_power_statecontrol_facade.SuspendPoweroff"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        try:
-            response = self.send_command(test_id,
-                                         test_cmd,
-                                         test_args,
-                                         response_timeout=timeout)
-        except (requests.exceptions.ReadTimeout,
-                http.client.RemoteDisconnected, base_lib.DeviceOffline):
-            return
-        return response
+        return self.send_command(test_cmd, test_args, response_timeout=timeout)
 
     def suspendMexec(self, timeout=HW_PWR_STATE_CONTROL_TIMEOUT):
         """Call Suspend Mexec
@@ -98,17 +76,7 @@
         """
         test_cmd = "hardware_power_statecontrol_facade.SuspendMexec"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        try:
-            response = self.send_command(test_id,
-                                         test_cmd,
-                                         test_args,
-                                         response_timeout=timeout)
-        except (requests.exceptions.ReadTimeout,
-                http.client.RemoteDisconnected, base_lib.DeviceOffline):
-            return
-        return response
+        return self.send_command(test_cmd, test_args, response_timeout=timeout)
 
     def suspendRam(self, timeout=HW_PWR_STATE_CONTROL_TIMEOUT):
         """Call Suspend Ram
@@ -118,14 +86,4 @@
         """
         test_cmd = "hardware_power_statecontrol_facade.SuspendRam"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        try:
-            response = self.send_command(test_id,
-                                         test_cmd,
-                                         test_args,
-                                         response_timeout=timeout)
-        except (requests.exceptions.ReadTimeout,
-                http.client.RemoteDisconnected, base_lib.DeviceOffline):
-            return
-        return response
+        return self.send_command(test_cmd, test_args, response_timeout=timeout)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/hwinfo_lib.py b/acts/framework/acts/controllers/fuchsia_lib/hwinfo_lib.py
deleted file mode 100644
index 0868fd1..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/hwinfo_lib.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-import datetime
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaHwinfoLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def getDeviceInfo(self):
-        """Get's the hw info of the Fuchsia device under test.
-
-        Returns:
-            Dictionary, None if success, error if error.
-        """
-        test_cmd = "hwinfo_facade.HwinfoGetDeviceInfo"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getProductInfo(self):
-        """Get's the hw info of the Fuchsia device under test.
-
-        Returns:
-            Dictionary, None if success, error if error.
-        """
-        test_cmd = "hwinfo_facade.HwinfoGetProductInfo"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getBoardInfo(self):
-        """Get's the hw info of the Fuchsia device under test.
-
-        Returns:
-            Dictionary, None if success, error if error.
-        """
-        test_cmd = "hwinfo_facade.HwinfoGetBoardInfo"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/i2c_lib.py b/acts/framework/acts/controllers/fuchsia_lib/i2c_lib.py
deleted file mode 100644
index 739e6e8..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/i2c_lib.py
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaI2cLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def transfer(self, device_idx, segments_is_write, write_segments_data,
-                 read_segments_length):
-        """Gets the fuchsia.input.report.DeviceDescriptor for a given device.
-
-        Args:
-          device_idx: the integer device index to use, e.g. 6 for /dev/class/i2c/006.
-          segments_is_write: a list of bools specifying whether each segment is a read or a write.
-          write_segments_data: a list of write segments, where each segment is a list of bytes to write.
-          read_segments_length: a list of integers specifying the number of bytes in each read segment.
-
-        Returns:
-          The list of read segments received, or an error message if an error was encountered.
-        """
-        test_cmd = "i2c_facade.Transfer"
-        test_args = {
-            "device_idx": device_idx,
-            "segments_is_write": segments_is_write,
-            "write_segments_data": write_segments_data,
-            "read_segments_length": read_segments_length
-        }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/input_report_lib.py b/acts/framework/acts/controllers/fuchsia_lib/input_report_lib.py
deleted file mode 100644
index aa12321..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/input_report_lib.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaInputReportLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    """Gets the fuchsia.input.report.DeviceDescriptor for a given device.
-
-    Args:
-      vendor_id: the uint32 vendor ID to match against available input devices, or None to match any
-        vendor ID.
-      product_id: the uint32 product ID to match against available input devices, or None to match
-        any product ID.
-      version: the uint32 version to match against available input devices, or None to match any
-        version.
-
-    Returns:
-      The DeviceDescriptor object, or an error message if an error was encountered.
-    """
-
-    def getDescriptor(self, vendor_id=None, product_id=None, version=None):
-        test_cmd = 'input_report_facade.GetDescriptor'
-        test_args = {
-            'vendor_id': vendor_id,
-            'product_id': product_id,
-            'version': version
-        }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        return self.send_command(test_id, test_cmd, test_args)
-
-    """Gets the list of fuchsia.input.report.InputReports that were seen since the last call.
-
-    Args:
-      vendor_id: the uint32 vendor ID to match against available input devices, or None to match any
-        vendor ID.
-      product_id: the uint32 product ID to match against available input devices, or None to match
-        any product ID.
-      version: the uint32 version to match against available input devices, or None to match any
-        version.
-
-    Returns:
-      A list of InputReports, or an error message if an error was encountered.
-    """
-
-    def getReports(self, vendor_id=None, product_id=None, version=None):
-        test_cmd = 'input_report_facade.GetReports'
-        test_args = {
-            'vendor_id': vendor_id,
-            'product_id': product_id,
-            'version': version
-        }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/kernel_lib.py b/acts/framework/acts/controllers/fuchsia_lib/kernel_lib.py
deleted file mode 100644
index 210adf4..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/kernel_lib.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaKernelLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def getMemoryStats(self):
-        """ Gets memory stats.
-
-        Returns:
-            MemoryStats struct, prints an error message if error.
-        """
-        test_cmd = "kernel_facade.GetMemoryStats"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getCpuStats(self):
-        """ Gets CPU stats.
-
-        Returns:
-            CpuStats struct, prints an error message if error.
-        """
-        test_cmd = "kernel_facade.GetCpuStats"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getAllStats(self):
-        """ Gets memory and CPU stats.
-
-        Returns:
-            MemoryStats struct and CpuStats struct, prints an error message if error.
-        """
-        test_cmd = "kernel_facade.GetAllStats"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py
index e7ca026..3fab8bc 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py
@@ -37,7 +37,7 @@
             List of dicts, one for each interface, containing interface
             information
         """
-        response = self.device.netstack_lib.netstackListInterfaces()
+        response = self.device.sl4f.netstack_lib.netstackListInterfaces()
         if response.get('error'):
             raise NetstackControllerError(
                 'Failed to get network interfaces list: %s' %
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 d50f726..5b99fc3 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
@@ -72,7 +72,7 @@
         """
 
         # Retrieve WLAN interface IDs
-        response = self.device.wlan_lib.wlanGetIfaceIdList()
+        response = self.device.sl4f.wlan_lib.wlanGetIfaceIdList()
         if response.get('error'):
             raise WlanControllerError('Failed to get WLAN iface ids: %s' %
                                       response['error'])
@@ -84,7 +84,7 @@
         # Use IDs to get WLAN interface info and mac addresses
         wlan_ifaces_by_mac = {}
         for id in wlan_iface_ids:
-            response = self.device.wlan_lib.wlanQueryInterface(id)
+            response = self.device.sl4f.wlan_lib.wlanQueryInterface(id)
             if response.get('error'):
                 raise WlanControllerError(
                     'Failed to query wlan iface id %s: %s' %
@@ -139,7 +139,7 @@
             ConnectionError - failure to query PHYs
         """
         self.log.info('Setting DUT country code to %s' % country_code)
-        country_code_response = self.device.regulatory_region_lib.setRegion(
+        country_code_response = self.device.sl4f.regulatory_region_lib.setRegion(
             country_code)
         if country_code_response.get('error'):
             raise EnvironmentError(
@@ -148,7 +148,7 @@
 
         self.log.info('Verifying DUT country code was correctly set to %s.' %
                       country_code)
-        phy_ids_response = self.device.wlan_lib.wlanPhyIdList()
+        phy_ids_response = self.device.sl4f.wlan_lib.wlanPhyIdList()
         if phy_ids_response.get('error'):
             raise ConnectionError('Failed to get phy ids from DUT. Error: %s' %
                                   (country_code, phy_ids_response['error']))
@@ -156,7 +156,8 @@
         end_time = time.time() + TIME_TO_WAIT_FOR_COUNTRY_CODE
         while time.time() < end_time:
             for id in phy_ids_response['result']:
-                get_country_response = self.device.wlan_lib.wlanGetCountry(id)
+                get_country_response = self.device.sl4f.wlan_lib.wlanGetCountry(
+                    id)
                 if get_country_response.get('error'):
                     raise ConnectionError(
                         'Failed to query PHY ID (%s) for country. Error: %s' %
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
index 53c5839..133cde3 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
@@ -14,15 +14,14 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import requests
+import subprocess
 import time
 
 from acts import logger
 from acts import signals
 
-import typing
-if typing.TYPE_CHECKING:
-    from acts.controllers.fuchsia_device import FuchsiaDevice
+from acts.controllers.fuchsia_lib.ffx import FFX, FFXError, FFXTimeout
+from acts.controllers.fuchsia_lib.sl4f import SL4F
 
 SAVED_NETWORKS = "saved_networks"
 CLIENT_STATE = "client_connections_state"
@@ -34,6 +33,8 @@
 STATE_DISCONNECTED = 'Disconnected'
 STATE_CONNECTION_STOPPED = 'ConnectionStopped'
 
+FUCHSIA_DEFAULT_WLAN_CONFIGURE_TIMEOUT = 30
+
 
 class WlanPolicyControllerError(signals.ControllerError):
     pass
@@ -44,27 +45,33 @@
     FuchsiaDevice object.
     """
 
-    def __init__(self, fuchsia_device):
-        self.device: FuchsiaDevice = fuchsia_device
-        self.log = logger.create_tagged_trace_logger(
-            'WlanPolicyController for FuchsiaDevice | %s' % self.device.ip)
+    def __init__(self, sl4f: SL4F, ffx: FFX):
         self.client_controller = False
         self.preserved_networks_and_client_state = None
         self.policy_configured = False
-        self._paused_session = False
+        self.sl4f = sl4f
+        self.ffx = ffx
+        self.log = logger.create_tagged_trace_logger(
+            f'WlanPolicyController | {ffx.ip}')
 
-    def _configure_wlan(self, preserve_saved_networks, timeout=15):
+    # TODO(b/231252355): Lower default timeout to 15s once ffx becomes more
+    # performant and/or reliable.
+    def configure_wlan(
+            self,
+            preserve_saved_networks: bool,
+            timeout_sec: int = FUCHSIA_DEFAULT_WLAN_CONFIGURE_TIMEOUT) -> None:
         """Sets up wlan policy layer.
 
         Args:
-            preserve_saved_networks: bool, whether to clear existing saved
+            preserve_saved_networks: whether to clear existing saved
                 networks and client state, to be restored at test close.
+            timeout: time to wait for device to configure WLAN.
         """
-        end_time = time.time() + timeout
+        end_time_sec = time.time() + timeout_sec
 
         # Kill basemgr (Component v1 version of session manager)
-        while time.time() < end_time:
-            response = self.device.basemgr_lib.killBasemgr()
+        while time.time() < end_time_sec:
+            response = self.sl4f.basemgr_lib.killBasemgr()
             if not response.get('error'):
                 self.log.debug('Basemgr kill call successfully issued.')
                 break
@@ -75,20 +82,28 @@
                 'Failed to issue successful basemgr kill call.')
 
         # Stop the session manager, which also holds the Policy controller.
-        response = self.device.session_manager_lib.pauseSession()
-        if response.get('error'):
-            self.log.error('Failed to stop the session.')
-            raise WlanPolicyControllerError(response['error'])
-        else:
-            if response.get('result') == 'Success':
-                self._paused_session = True
-            self.log.debug(f"Paused session: {response.get('result')}")
+        try:
+            result = self.ffx.run(
+                'component destroy /core/session-manager/session:session',
+                skip_status_code_check=True)
+
+            if result.returncode == 0:
+                self.log.debug(f"Stopped session: {result.stdout}.")
+            else:
+                if (b'InstanceNotFound' in result.stderr
+                        or b'instance was not found' in result.stderr):
+                    self.log.debug(f'Instance was not found: {result.stderr}.')
+                else:
+                    raise WlanPolicyControllerError(
+                        f'Failed to stop the session: {result.stderr}.')
+        except FFXTimeout or FFXError as e:
+            raise WlanPolicyControllerError from e
 
         # Acquire control of policy layer
         controller_errors = []
-        while time.time() < end_time:
+        while time.time() < end_time_sec:
             # Create a client controller
-            response = self.device.wlan_policy_lib.wlanCreateClientController()
+            response = self.sl4f.wlan_policy_lib.wlanCreateClientController()
             if response.get('error'):
                 controller_errors.append(response['error'])
                 self.log.debug(response['error'])
@@ -96,7 +111,7 @@
                 continue
             # Attempt to use the client controller (failure indicates a closed
             # channel, meaning the client controller was rejected.
-            response = self.device.wlan_policy_lib.wlanGetSavedNetworks()
+            response = self.sl4f.wlan_policy_lib.wlanGetSavedNetworks()
             if response.get('error'):
                 controller_errors.append(response['error'])
                 self.log.debug(response['error'])
@@ -127,21 +142,14 @@
                 'Failed to stop client connections during deconfiguration.')
         self.policy_configured = False
 
-    def _clean_up(self):
+    def clean_up(self) -> None:
         if self.preserved_networks_and_client_state:
             # It is possible for policy to have been configured before, but
             # deconfigured before test end. In this case, in must be setup
             # before restoring networks
             if not self.policy_configured:
-                self._configure_wlan()
+                self.configure_wlan()
             self.restore_preserved_networks_and_client_state()
-        if self._paused_session:
-            response = self.device.session_manager_lib.resumeSession()
-            if response.get('error'):
-                self.log.warning('Failed to resume the session.')
-                self.log.warning(response['error'])
-            else:
-                self.log.debug(f"Resumed session: {response.get('result')}")
 
     def start_client_connections(self):
         """Allow device to connect to networks via policy layer (including
@@ -149,8 +157,7 @@
 
         Returns:
             True, if successful. False otherwise."""
-        start_response = self.device.wlan_policy_lib.wlanStartClientConnections(
-        )
+        start_response = self.sl4f.wlan_policy_lib.wlanStartClientConnections()
         if start_response.get('error'):
             self.log.error('Failed to start client connections. Err: %s' %
                            start_response['error'])
@@ -163,7 +170,7 @@
 
         Returns:
             True, if successful. False otherwise."""
-        stop_response = self.device.wlan_policy_lib.wlanStopClientConnections()
+        stop_response = self.sl4f.wlan_policy_lib.wlanStopClientConnections()
         if stop_response.get('error'):
             self.log.error('Failed to stop client connections. Err: %s' %
                            stop_response['error'])
@@ -178,7 +185,7 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
             timeout: int, time in seconds to wait for connection
 
@@ -189,7 +196,7 @@
         if not self.save_network(ssid, security, password=password):
             return False
         # Make connect call and check response
-        self.device.wlan_policy_lib.wlanSetNewListener()
+        self.sl4f.wlan_policy_lib.wlanSetNewListener()
         if not self.send_connect_command(ssid, security):
             return False
         return self.wait_for_connect(ssid, security, timeout=timeout)
@@ -208,7 +215,7 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
             timeout: int, time in seconds to wait for connection
 
@@ -232,7 +239,7 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
             state: string, The connection state we are expecting, ie "Disconnected" or
                 "Failed"
@@ -243,7 +250,7 @@
         Returns:
             True, if successful. False otherwise.
         """
-        self.device.wlan_policy_lib.wlanSetNewListener()
+        self.sl4f.wlan_policy_lib.wlanSetNewListener()
         if not self.remove_network(ssid, security_type, password=password):
             return False
         return self.wait_for_disconnect(ssid,
@@ -259,7 +266,7 @@
         Returns:
             True, if successful. False otherwise.
         """
-        self.device.wlan_policy_lib.wlanSetNewListener()
+        self.sl4f.wlan_policy_lib.wlanSetNewListener()
         if not self.remove_all_networks():
             self.log.error('Failed to remove all networks. Cannot continue to '
                            'wait_for_no_connections.')
@@ -271,13 +278,13 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
 
         Returns:
             True, if successful. False otherwise.
         """
-        save_response = self.device.wlan_policy_lib.wlanSaveNetwork(
+        save_response = self.sl4f.wlan_policy_lib.wlanSaveNetwork(
             ssid, security_type, target_pwd=password)
         if save_response.get('error'):
             self.log.error('Failed to save network %s with error: %s' %
@@ -290,13 +297,13 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
 
         Returns:
             True, if successful. False otherwise.
         """
-        remove_response = self.device.wlan_policy_lib.wlanRemoveNetwork(
+        remove_response = self.sl4f.wlan_policy_lib.wlanRemoveNetwork(
             ssid, security_type, target_pwd=password)
         if remove_response.get('error'):
             self.log.error('Failed to remove network %s with error: %s' %
@@ -310,8 +317,7 @@
         Returns:
             True, if successful. False otherwise.
         """
-        remove_all_response = self.device.wlan_policy_lib.wlanRemoveAllNetworks(
-        )
+        remove_all_response = self.sl4f.wlan_policy_lib.wlanRemoveAllNetworks()
         if remove_all_response.get('error'):
             self.log.error('Error occurred removing all networks: %s' %
                            remove_all_response['error'])
@@ -327,7 +333,7 @@
         Raises:
             WlanPolicyControllerError, if retrieval fails.
         """
-        saved_networks_response = self.device.wlan_policy_lib.wlanGetSavedNetworks(
+        saved_networks_response = self.sl4f.wlan_policy_lib.wlanGetSavedNetworks(
         )
         if saved_networks_response.get('error'):
             raise WlanPolicyControllerError(
@@ -342,13 +348,13 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             password: string, the credential of the network if applicable
 
         Returns:
             True, if command send successfully. False otherwise.
         """
-        connect_response = self.device.wlan_policy_lib.wlanConnect(
+        connect_response = self.sl4f.wlan_policy_lib.wlanConnect(
             ssid, security_type)
         if connect_response.get('error'):
             self.log.error(
@@ -361,7 +367,7 @@
         """ Wait until the device has connected to the specified network.
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             timeout: int, seconds to wait for a update showing connection
         Returns:
             True if we see a connect to the network, False otherwise.
@@ -373,15 +379,15 @@
             time_left = max(1, int(end_time - time.time()))
 
             try:
-                update = self.device.wlan_policy_lib.wlanGetUpdate(
+                update = self.sl4f.wlan_policy_lib.wlanGetUpdate(
                     timeout=time_left)
-            except requests.exceptions.Timeout:
+            except TimeoutError:
                 self.log.error('Timed out waiting for response from device '
                                'while waiting for network with SSID "%s" to '
                                'connect. Device took too long to connect or '
                                'the request timed out for another reason.' %
                                ssid)
-                self.device.wlan_policy_lib.wlanSetNewListener()
+                self.sl4f.wlan_policy_lib.wlanSetNewListener()
                 return False
             if update.get('error'):
                 # This can occur for many reasons, so it is not necessarily a
@@ -418,7 +424,7 @@
 
         Args:
             ssid: string, the network name
-            security: string, security type of network (see wlan_policy_lib)
+            security: string, security type of network (see sl4f.wlan_policy_lib)
             state: string, The connection state we are expecting, ie "Disconnected" or
                 "Failed"
             status: string, The disconnect status we expect, it "ConnectionStopped" or
@@ -436,15 +442,15 @@
         while time.time() < end_time:
             time_left = max(1, int(end_time - time.time()))
             try:
-                update = self.device.wlan_policy_lib.wlanGetUpdate(
+                update = self.sl4f.wlan_policy_lib.wlanGetUpdate(
                     timeout=time_left)
-            except requests.exceptions.Timeout:
+            except TimeoutError:
                 self.log.error(
                     'Timed out waiting for response from device '
                     'while waiting for network with SSID "%s" to '
                     'disconnect. Device took too long to disconnect '
                     'or the request timed out for another reason.' % ssid)
-                self.device.wlan_policy_lib.wlanSetNewListener()
+                self.sl4f.wlan_policy_lib.wlanSetNewListener()
                 return False
 
             if update.get('error'):
@@ -506,18 +512,18 @@
         # If there are already no existing connections when this function is called,
         # then an update won't be generated by the device, and we'll time out.
         # Force an update by getting a new listener.
-        self.device.wlan_policy_lib.wlanSetNewListener()
+        self.sl4f.wlan_policy_lib.wlanSetNewListener()
         end_time = time.time() + timeout
         while time.time() < end_time:
             time_left = max(1, int(end_time - time.time()))
             try:
-                update = self.device.wlan_policy_lib.wlanGetUpdate(
+                update = self.sl4f.wlan_policy_lib.wlanGetUpdate(
                     timeout=time_left)
-            except requests.exceptions.Timeout:
+            except TimeoutError:
                 self.log.info(
                     "Timed out getting status update while waiting for all"
                     " connections to end.")
-                self.device.wlan_policy_lib.wlanSetNewListener()
+                self.sl4f.wlan_policy_lib.wlanSetNewListener()
                 return False
 
             if update["error"] != None:
@@ -544,7 +550,7 @@
         """
         # Save preexisting saved networks
         preserved_networks_and_state = {}
-        saved_networks_response = self.device.wlan_policy_lib.wlanGetSavedNetworks(
+        saved_networks_response = self.sl4f.wlan_policy_lib.wlanGetSavedNetworks(
         )
         if saved_networks_response.get('error'):
             raise WlanPolicyControllerError(
@@ -560,8 +566,8 @@
                 'Failed to clear networks and disconnect at FuchsiaDevice creation.'
             )
 
-        self.device.wlan_policy_lib.wlanSetNewListener()
-        update_response = self.device.wlan_policy_lib.wlanGetUpdate()
+        self.sl4f.wlan_policy_lib.wlanSetNewListener()
+        update_response = self.sl4f.wlan_policy_lib.wlanGetUpdate()
         update_result = update_response.get('result', {})
         if update_result.get('state'):
             preserved_networks_and_state[CLIENT_STATE] = update_result['state']
diff --git a/acts/framework/acts/controllers/fuchsia_lib/light_lib.py b/acts/framework/acts/controllers/fuchsia_lib/light_lib.py
deleted file mode 100644
index d0ad168..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/light_lib.py
+++ /dev/null
@@ -1,342 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class RgbValue:
-    # use __dict__ to send in json
-    def __init__(self, r, g, b):
-        self.red = r
-        self.green = g
-        self.blue = b
-
-
-class FuchsiaLightLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def getNumLights(self):
-        """ Gets the total number of physical lights on the Fuchsia device
-        under test.
-
-        Returns:
-            Integer (number of lights), prints an error message if error.
-        """
-        test_cmd = "light_facade.GetNumLights"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getNumLightGroups(self):
-        """ Gets the total number of light groups on the Fuchsia device
-        under test.
-
-        Returns:
-            Integer (number of light groups), prints an error message if error.
-        """
-        test_cmd = "light_facade.GetNumLightGroups"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getInfo(self, index):
-        """ Gets info (name and capability) for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-
-        Returns:
-            The Info object, prints an error message if error.
-        """
-        test_cmd = "light_facade.GetInfo"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getCurrentSimpleValue(self, index):
-        """ Gets the current simple value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-
-        Returns:
-            Boolean. True if the light is ON, False if the light is OFF.
-            If the capability 'SIMPLE' is not supported by this light, fails and prints
-            error message.
-            Use GetInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetCurrentSimpleValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setSimpleValue(self, index, value):
-        """ Sets the simple value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            value: boolean, True for ON, False for OFF
-
-        Returns:
-            None if success, prints error message if error (e.g. capability 'SIMPLE'
-            is not supported by the light).
-        """
-        test_cmd = "light_facade.SetSimpleValue"
-        test_args = {"index": index, "value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getCurrentBrightnessValue(self, index):
-        """ Gets the current brightness value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-
-        Returns:
-            uint8. A value 0-255 inclusive indicating the brightness of the light.
-            If the capability 'BRIGHTNESS' is not supported by this light, fails and prints
-            error message.
-            Use GetInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetCurrentBrightnessValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setBrightnessValue(self, index, value):
-        """ Sets the brightness value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            value: uint8, 0-255 inclusive indicating the brightness of the light
-
-        Returns:
-            None if success, prints error message if error (e.g. capability
-            'BRIGHTNESS' is not supported by the light).
-        """
-        test_cmd = "light_facade.SetBrightnessValue"
-        test_args = {"index": index, "value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getCurrentRgbValue(self, index):
-        """ Gets the current RGB value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-
-        Returns:
-            The RGB object indicating the RGB value of the light.
-            If the capability 'RGB' is not supported by this light, fails and prints
-            error message.
-            Use GetInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetCurrentRgbValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setRgbValue(self, index, value):
-        """ Sets the RGB value for a single light on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            value: an RGB object
-
-        Returns:
-            None if success, prints error message if error (e.g. capability 'RGB'
-            is not supported by the light).
-        """
-        test_cmd = "light_facade.SetRgbValue"
-        test_args = {"index": index, "value": value}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getGroupInfo(self, index):
-        """ Gets group info (name, number of lights, and capability) for a light
-        group on the Fuchsia device under test.
-
-        Args:
-            index: uint32, index of the light group defined by board, must be less
-                   than value returned by getNumLightGroups
-
-        Returns:
-            The GroupInfo object, prints an error message if error.
-        """
-        test_cmd = "light_facade.GetGroupInfo"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getGroupCurrentSimpleValue(self, index):
-        """ Gets the current simple values for the light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light group defined by board, must be less than
-                   value returned by getNumLightGroups
-
-        Returns:
-            Vector of booleans, each indicating whether or not the light is on.
-            If the capability 'SIMPLE' is not supported by the light group, fails and prints
-            error message.
-            Use GetGroupInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetGroupCurrentSimpleValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setGroupSimpleValue(self, index, values):
-        """ Sets the simple value for a light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            values: a vector of booleans, each has True for ON, False for OFF
-
-        Returns:
-            None if success, prints error message if error (e.g. capability 'SIMPLE'
-            is not supported by the light group).
-        """
-        test_cmd = "light_facade.SetGroupSimpleValue"
-        test_args = {"index": index, "values": values}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getGroupCurrentBrightnessValue(self, index):
-        """ Gets the current brightness values for the light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light group defined by board, must be less than
-                   value returned by getNumLightGroups
-
-        Returns:
-            Vector of uint8, each indicating the brightness of the light.
-            If the capability 'SIMPLE' is not supported by the light group, fails and prints
-            error message.
-            Use GetGroupInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetGroupCurrentBrightnessValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setGroupBrightnessValue(self, index, values):
-        """ Sets the brightness value for a light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            values: a vector of uint8s, each indicating the brightness of a light.
-
-        Returns:
-            None if success, prints error message if error (e.g. capability 'BRIGHTNESS'
-            is not supported by the light group).
-        """
-        test_cmd = "light_facade.SetGroupBrightnessValue"
-        test_args = {"index": index, "values": values}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getGroupCurrentRgbValue(self, index):
-        """ Gets the current RGB values for the light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light group defined by board, must be less than
-                   value returned by getNumLightGroups
-
-        Returns:
-            Vector of RGB objects, each indicating the RGB value of the light.
-            If the capability 'RGB' is not supported by the light group, fails and prints
-            error message.
-            Use GetGroupInfo to check if light supports this operation.
-        """
-        test_cmd = "light_facade.GetGroupCurrentRgbValue"
-        test_args = {"index": index}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def setGroupRgbValue(self, index, values):
-        """ Sets the RGB value for a light group on the Fuchsia device
-        under test.
-
-        Args:
-            index: uint32, index of the light defined by board, must be less than
-                   value returned by getNumLights
-            values: a vector of RGB objects, each indicating the RGB value of a light.
-
-        Returns:
-            None if success, prints error message if error (e.g. capability 'RGB'
-            is not supported by the light group).
-        """
-        test_cmd = "light_facade.SetGroupRgbValue"
-        test_args = {"index": index, "values": values}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/location/regulatory_region_lib.py b/acts/framework/acts/controllers/fuchsia_lib/location/regulatory_region_lib.py
index b755db8..8519785 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/location/regulatory_region_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/location/regulatory_region_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaRegulatoryRegionLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "location_regulatory_region")
 
     # TODO(fxb/46727): Provide an analagous call to check the region
     # configured into the driver.
@@ -36,7 +35,5 @@
         """
         test_cmd = "location_regulatory_region_facade.set_region"
         test_args = {"region": region_code}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py b/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
index 78a9dd4..25826e3 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
@@ -20,10 +20,9 @@
 
 
 class FuchsiaLoggingLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "logging")
 
     def logE(self, message):
         """Log a message of level Error directly to the syslog.
@@ -38,10 +37,8 @@
         test_args = {
             "message": '[%s] %s' % (datetime.datetime.now(), message),
         }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def logI(self, message):
         """Log a message of level Info directly to the syslog.
@@ -54,10 +51,8 @@
         """
         test_cmd = "logging_facade.LogInfo"
         test_args = {"message": '[%s] %s' % (datetime.datetime.now(), message)}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def logW(self, message):
         """Log a message of level Warning directly to the syslog.
@@ -70,7 +65,5 @@
         """
         test_cmd = "logging_facade.LogWarn"
         test_args = {"message": '[%s] %s' % (datetime.datetime.now(), message)}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py b/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
index 173127c..9344f7f 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
@@ -18,10 +18,9 @@
 
 
 class FuchsiaNetstackLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
+
+    def __init__(self, addr: str) -> None:
+        super().__init__(addr, "netstack")
 
     def netstackListInterfaces(self):
         """ListInterfaces command
@@ -31,10 +30,8 @@
         """
         test_cmd = "netstack_facade.ListInterfaces"
         test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def enableInterface(self, id):
         """Enable Interface
@@ -47,10 +44,8 @@
         """
         test_cmd = "netstack_facade.EnableInterface"
         test_args = {"identifier": id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
 
     def disableInterface(self, id):
         """Disable Interface
@@ -63,7 +58,5 @@
         """
         test_cmd = "netstack_facade.DisableInterface"
         test_args = {"identifier": id}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
 
-        return self.send_command(test_id, test_cmd, test_args)
+        return self.send_command(test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/package_server.py b/acts/framework/acts/controllers/fuchsia_lib/package_server.py
new file mode 100644
index 0000000..1bc0448
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/package_server.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python3
+#
+#   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.
+#   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.
+
+import json
+import os
+import shutil
+import socket
+import subprocess
+import tarfile
+import tempfile
+
+from dataclasses import dataclass
+from datetime import datetime
+from typing import TextIO, List, Optional
+
+from acts import context
+from acts import logger
+from acts import signals
+from acts import utils
+
+from acts.controllers.fuchsia_lib.ssh import FuchsiaSSHError, SSHProvider
+from acts.controllers.fuchsia_lib.utils_lib import wait_for_port
+from acts.tracelogger import TraceLogger
+
+DEFAULT_FUCHSIA_REPO_NAME = "fuchsia.com"
+PM_SERVE_STOP_TIMEOUT_SEC = 5
+
+
+class PackageServerError(signals.TestAbortClass):
+    pass
+
+
+def random_port() -> int:
+    s = socket.socket()
+    s.bind(('', 0))
+    return s.getsockname()[1]
+
+
+@dataclass
+class Route:
+    """Represent a route in the routing table."""
+    preferred_source: Optional[str]
+
+
+def find_routes_to(dest_ip) -> List[Route]:
+    """Find the routes used to reach a destination.
+
+    Look through the routing table for the routes that would be used without
+    sending any packets. This is especially helpful for when the device is
+    currently unreachable.
+
+    Only natively supported on Linux. MacOS has iproute2mac, but it doesn't
+    support JSON formatted output.
+
+    TODO(http://b/238924195): Add support for MacOS.
+
+    Args:
+        dest_ip: IP address of the destination
+
+    Throws:
+        CalledProcessError: if the ip command returns a non-zero exit code
+        JSONDecodeError: if the ip command doesn't return JSON
+
+    Returns:
+        Routes with destination to dest_ip.
+    """
+    resp = subprocess.run(f"ip -json route get {dest_ip}".split(),
+                          capture_output=True,
+                          check=True)
+    routes = json.loads(resp.stdout)
+    return [Route(r.get("prefsrc")) for r in routes]
+
+
+def find_host_ip(device_ip: str) -> str:
+    """Find the host's source IP used to reach a device.
+
+    Not all host interfaces can talk to a given device. This limitation can
+    either be physical through hardware or virtual through routing tables.
+    Look through the routing table without sending any packets then return the
+    preferred source IP address.
+
+    Args:
+        device_ip: IP address of the device
+
+    Raises:
+        PackageServerError: if there are multiple or no routes to device_ip, or
+            if the route doesn't contain "prefsrc"
+
+    Returns:
+        The host IP used to reach device_ip.
+    """
+    routes = find_routes_to(device_ip)
+    if len(routes) != 1:
+        raise PackageServerError(
+            f"Expected only one route to {device_ip}, got {routes}")
+
+    route = routes[0]
+    if not route.preferred_source:
+        raise PackageServerError(f'Route does not contain "prefsrc": {route}')
+    return route.preferred_source
+
+
+class PackageServer:
+    """Package manager for Fuchsia; an interface to the "pm" CLI tool."""
+
+    def __init__(self, packages_archive_path: str) -> None:
+        """
+        Args:
+            packages_archive_path: Path to an archive containing the pm binary
+                and amber-files.
+        """
+        self.log: TraceLogger = logger.create_tagged_trace_logger("pm")
+
+        self._server_log: Optional[TextIO] = None
+        self._server_proc: Optional[subprocess.Popen] = None
+        self._log_path: Optional[str] = None
+
+        self._tmp_dir = tempfile.mkdtemp(prefix="packages-")
+        tar = tarfile.open(packages_archive_path, "r:gz")
+        tar.extractall(self._tmp_dir)
+
+        self._binary_path = os.path.join(self._tmp_dir, "pm")
+        self._packages_path = os.path.join(self._tmp_dir, "amber-files")
+        self._port = random_port()
+
+        self._assert_repo_has_not_expired()
+
+    def clean_up(self) -> None:
+        if self._server_proc:
+            self.stop_server()
+        if self._tmp_dir:
+            shutil.rmtree(self._tmp_dir)
+
+    def _assert_repo_has_not_expired(self) -> None:
+        """Abort if the repository metadata has expired.
+
+        Raises:
+            TestAbortClass: when the timestamp.json file has expired
+        """
+        with open(f'{self._packages_path}/repository/timestamp.json',
+                  'r') as f:
+            data = json.load(f)
+            expiresAtRaw = data["signed"]["expires"]
+            expiresAt = datetime.strptime(expiresAtRaw, '%Y-%m-%dT%H:%M:%SZ')
+            if expiresAt <= datetime.now():
+                raise signals.TestAbortClass(
+                    f'{self._packages_path}/repository/timestamp.json has expired on {expiresAtRaw}'
+                )
+
+    def start(self) -> None:
+        """Start the package server.
+
+        Does not check for errors; view the log file for any errors.
+        """
+        if self._server_proc:
+            self.log.warn(
+                "Skipping to start the server since it has already been started"
+            )
+            return
+
+        pm_command = f'{self._binary_path} serve -c 2 -repo {self._packages_path} -l :{self._port}'
+
+        root_dir = context.get_current_context().get_full_output_path()
+        epoch = utils.get_current_epoch_time()
+        time_stamp = logger.normalize_log_line_timestamp(
+            logger.epoch_to_log_line_timestamp(epoch))
+        self._log_path = os.path.join(root_dir, f'pm_server.{time_stamp}.log')
+
+        self._server_log = open(self._log_path, 'a+')
+        self._server_proc = subprocess.Popen(pm_command.split(),
+                                             preexec_fn=os.setpgrp,
+                                             stdout=self._server_log,
+                                             stderr=subprocess.STDOUT)
+        try:
+            wait_for_port('127.0.0.1', self._port)
+        except TimeoutError as e:
+            if self._server_log:
+                self._server_log.close()
+            if self._log_path:
+                with open(self._log_path, 'r') as f:
+                    logs = f.read()
+            raise TimeoutError(
+                f"pm serve failed to expose port {self._port}. Logs:\n{logs}"
+            ) from e
+
+        self.log.info(f'Serving packages on port {self._port}')
+
+    def configure_device(self,
+                         ssh: SSHProvider,
+                         repo_name=DEFAULT_FUCHSIA_REPO_NAME) -> None:
+        """Configure the device to use this package server.
+
+        Args:
+            ssh: Device SSH transport channel
+            repo_name: Name of the repo to alias this package server
+        """
+        # Remove any existing repositories that may be stale.
+        try:
+            ssh.run(f'pkgctl repo rm fuchsia-pkg://{repo_name}')
+        except FuchsiaSSHError as e:
+            if 'NOT_FOUND' not in e.result.stderr:
+                raise e
+
+        # Configure the device with the new repository.
+        host_ip = find_host_ip(ssh.config.host_name)
+        repo_url = f"http://{host_ip}:{self._port}"
+        ssh.run(
+            f"pkgctl repo add url -f 2 -n {repo_name} {repo_url}/config.json")
+        self.log.info(
+            f'Added repo "{repo_name}" as {repo_url} on device {ssh.config.host_name}'
+        )
+
+    def stop_server(self) -> None:
+        """Stop the package server."""
+        if not self._server_proc:
+            self.log.warn(
+                "Skipping to stop the server since it hasn't been started yet")
+            return
+
+        self._server_proc.terminate()
+        try:
+            self._server_proc.wait(timeout=PM_SERVE_STOP_TIMEOUT_SEC)
+        except subprocess.TimeoutExpired:
+            self.log.warn(
+                f"Taking over {PM_SERVE_STOP_TIMEOUT_SEC}s to stop. Killing the server"
+            )
+            self._server_proc.kill()
+            self._server_proc.wait(timeout=PM_SERVE_STOP_TIMEOUT_SEC)
+        finally:
+            if self._server_log:
+                self._server_log.close()
+
+        self._server_proc = None
+        self._log_path = None
+        self._server_log = None
diff --git a/acts/framework/acts/controllers/fuchsia_lib/ram_lib.py b/acts/framework/acts/controllers/fuchsia_lib/ram_lib.py
deleted file mode 100644
index ce8bb73..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/ram_lib.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaRamLib(BaseLib):
-    def __init__(self, addr, tc, client_id):
-        self.address = addr
-        self.test_counter = tc
-        self.client_id = client_id
-
-    def measureBandwidth(self, cycles_to_measure, channels):
-        """ Measures the DDR bandwidth on the specified channels.
-
-        Args:
-            cycles_to_measure: How many bus cycles to perform the measurement over.
-            channels: An array of 8 uint64, specifying which ports to aggregate
-                      for each channel.
-
-        Returns:
-            BandwidthInfo struct, prints an error message if error.
-        """
-        test_cmd = "ram_facade.MeasureBandwidth"
-        test_args = {
-            "values": {
-                "cycles_to_measure": cycles_to_measure,
-                "channels": channels
-            }
-        }
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
-
-    def getDdrWindowingResults(self):
-        """ Retrieves the results from the DDR Windowing tool, which runs in
-            the bootloader.
-
-        Returns:
-            The register value, prints an error message if error.
-        """
-        test_cmd = "ram_facade.GetDdrWindowingResults"
-        test_args = {}
-        test_id = self.build_id(self.test_counter)
-        self.test_counter += 1
-
-        return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
deleted file mode 100644
index fc03c14..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2021 - 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.
-#   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.
-
-import typing
-if typing.TYPE_CHECKING:
-    from acts.controllers.fuchsia_device import FuchsiaDevice
-
-
-class FuchsiaSessionManagerLib():
-    def __init__(self, fuchsia_device):
-        self.device: FuchsiaDevice = fuchsia_device
-
-    def resumeSession(self):
-        """Resumes a previously paused session
-
-        Returns:
-            Dictionary:
-                error: None, unless an error occurs
-                result: 'Success' or None if error
-        """
-        try:
-            self.device.ffx.run(
-                "component start /core/session-manager/session:session")
-            return {'error': None, 'result': 'Success'}
-        except Exception as e:
-            return {'error': e, 'result': None}
-
-    def pauseSession(self):
-        """Pause the session, allowing for later resumption
-
-        Returns:
-            Dictionary:
-                error: None, unless an error occurs
-                result: 'Success', 'NoSessionToPause', or None if error
-        """
-        result = self.device.ffx.run(
-            "component stop -r /core/session-manager/session:session",
-            skip_status_code_check=True)
-
-        if result.exit_status == 0:
-            return {'error': None, 'result': 'Success'}
-        else:
-            if "InstanceNotFound" in result.stderr:
-                return {'error': None, 'result': 'NoSessionToPause'}
-            else:
-                return {'error': result, 'result': None}
diff --git a/acts/framework/acts/controllers/fuchsia_lib/sl4f.py b/acts/framework/acts/controllers/fuchsia_lib/sl4f.py
new file mode 100644
index 0000000..69bf2f5
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/sl4f.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python3
+#
+#   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.
+#   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.
+
+import ipaddress
+
+from acts import logger
+from acts.controllers.fuchsia_lib import utils_lib
+from acts.controllers.fuchsia_lib.audio_lib import FuchsiaAudioLib
+from acts.controllers.fuchsia_lib.basemgr_lib import FuchsiaBasemgrLib
+from acts.controllers.fuchsia_lib.bt.avdtp_lib import FuchsiaAvdtpLib
+from acts.controllers.fuchsia_lib.bt.ble_lib import FuchsiaBleLib
+from acts.controllers.fuchsia_lib.bt.bts_lib import FuchsiaBtsLib
+from acts.controllers.fuchsia_lib.bt.gattc_lib import FuchsiaGattcLib
+from acts.controllers.fuchsia_lib.bt.gatts_lib import FuchsiaGattsLib
+from acts.controllers.fuchsia_lib.bt.hfp_lib import FuchsiaHfpLib
+from acts.controllers.fuchsia_lib.bt.rfcomm_lib import FuchsiaRfcommLib
+from acts.controllers.fuchsia_lib.bt.sdp_lib import FuchsiaProfileServerLib
+from acts.controllers.fuchsia_lib.hardware_power_statecontrol_lib import FuchsiaHardwarePowerStatecontrolLib
+from acts.controllers.fuchsia_lib.location.regulatory_region_lib import FuchsiaRegulatoryRegionLib
+from acts.controllers.fuchsia_lib.logging_lib import FuchsiaLoggingLib
+from acts.controllers.fuchsia_lib.netstack.netstack_lib import FuchsiaNetstackLib
+from acts.controllers.fuchsia_lib.ssh import SSHProvider, FuchsiaSSHError
+from acts.controllers.fuchsia_lib.wlan_ap_policy_lib import FuchsiaWlanApPolicyLib
+from acts.controllers.fuchsia_lib.wlan_deprecated_configuration_lib import FuchsiaWlanDeprecatedConfigurationLib
+from acts.controllers.fuchsia_lib.wlan_lib import FuchsiaWlanLib
+from acts.controllers.fuchsia_lib.wlan_policy_lib import FuchsiaWlanPolicyLib
+
+DEFAULT_SL4F_PORT = 80
+START_SL4F_V2_CMD = 'start_sl4f'
+
+
+class SL4F:
+    """Module for Fuchsia devices to interact with the SL4F tool.
+
+    Attributes:
+        ssh: SSHProvider transport to start and stop SL4F.
+        address: http address for SL4F server including SL4F port.
+        log: Logger for the device-specific instance of SL4F.
+    """
+
+    def __init__(self, ssh: SSHProvider,
+                 port: int = DEFAULT_SL4F_PORT) -> None:
+        """
+        Args:
+            ssh: SSHProvider transport to start and stop SL4F.
+            port: Port for the SL4F server to listen on.
+        """
+        host = ipaddress.ip_address(ssh.config.host_name)
+        if host.version == 4:
+            self.address = f'http://{host}:{port}'
+        elif host.version == 6:
+            self.address = f'http://[{host}]:{port}'
+
+        self.log = logger.create_tagged_trace_logger(f"SL4F | {self.address}")
+
+        try:
+            ssh.run(START_SL4F_V2_CMD).stdout
+        except FuchsiaSSHError:
+            # TODO(fxbug.dev/99331) Remove support to run SL4F in CFv1 mode
+            # once ACTS no longer use images that comes with only CFv1 SL4F.
+            self.log.warn(
+                "Running SL4F in CFv1 mode, "
+                "this is deprecated for images built after 5/9/2022, "
+                "see https://fxbug.dev/77056 for more info.")
+            ssh.stop_v1_component("sl4f")
+            ssh.start_v1_component("sl4f")
+
+        utils_lib.wait_for_port(str(host), port)
+        self._init_libraries()
+        self._verify_sl4f_connection()
+
+    def _init_libraries(self) -> None:
+        # Grab commands from FuchsiaAudioLib
+        self.audio_lib = FuchsiaAudioLib(self.address)
+
+        # Grab commands from FuchsiaAvdtpLib
+        self.avdtp_lib = FuchsiaAvdtpLib(self.address)
+
+        # Grab commands from FuchsiaHfpLib
+        self.hfp_lib = FuchsiaHfpLib(self.address)
+
+        # Grab commands from FuchsiaRfcommLib
+        self.rfcomm_lib = FuchsiaRfcommLib(self.address)
+
+        # Grab commands from FuchsiaBasemgrLib
+        self.basemgr_lib = FuchsiaBasemgrLib(self.address)
+
+        # Grab commands from FuchsiaBleLib
+        self.ble_lib = FuchsiaBleLib(self.address)
+
+        # Grab commands from FuchsiaBtsLib
+        self.bts_lib = FuchsiaBtsLib(self.address)
+
+        # Grab commands from FuchsiaGattcLib
+        self.gattc_lib = FuchsiaGattcLib(self.address)
+
+        # Grab commands from FuchsiaGattsLib
+        self.gatts_lib = FuchsiaGattsLib(self.address)
+
+        # Grab commands from FuchsiaHardwarePowerStatecontrolLib
+        self.hardware_power_statecontrol_lib = (
+            FuchsiaHardwarePowerStatecontrolLib(self.address))
+
+        # Grab commands from FuchsiaLoggingLib
+        self.logging_lib = FuchsiaLoggingLib(self.address)
+
+        # Grab commands from FuchsiaNetstackLib
+        self.netstack_lib = FuchsiaNetstackLib(self.address)
+
+        # Grab commands from FuchsiaProfileServerLib
+        self.sdp_lib = FuchsiaProfileServerLib(self.address)
+
+        # Grab commands from FuchsiaRegulatoryRegionLib
+        self.regulatory_region_lib = FuchsiaRegulatoryRegionLib(self.address)
+
+        # Grabs command from FuchsiaWlanDeprecatedConfigurationLib
+        self.wlan_deprecated_configuration_lib = (
+            FuchsiaWlanDeprecatedConfigurationLib(self.address))
+
+        # Grab commands from FuchsiaWlanLib
+        self.wlan_lib = FuchsiaWlanLib(self.address)
+
+        # Grab commands from FuchsiaWlanApPolicyLib
+        self.wlan_ap_policy_lib = FuchsiaWlanApPolicyLib(self.address)
+
+        # Grab commands from FuchsiaWlanPolicyLib
+        self.wlan_policy_lib = FuchsiaWlanPolicyLib(self.address)
+
+    def _verify_sl4f_connection(self) -> None:
+        """Verify SL4F commands can run on server."""
+
+        self.log.info('Verifying SL4F commands can run.')
+        try:
+            self.wlan_lib.wlanGetIfaceIdList()
+        except Exception as err:
+            raise ConnectionError(
+                f'Failed to connect and run command via SL4F. Err: {err}')
diff --git a/acts/framework/acts/controllers/fuchsia_lib/ssh.py b/acts/framework/acts/controllers/fuchsia_lib/ssh.py
new file mode 100644
index 0000000..59ebfc9
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/ssh.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python3
+#
+#   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.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0SSHResults
+#
+#   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.
+
+import subprocess
+import time
+
+from dataclasses import dataclass
+from typing import List, Union
+
+from acts import logger
+from acts import signals
+
+DEFAULT_SSH_USER: str = "fuchsia"
+DEFAULT_SSH_PORT: int = 22
+DEFAULT_SSH_TIMEOUT_SEC: int = 60
+DEFAULT_SSH_CONNECT_TIMEOUT_SEC: int = 30
+DEFAULT_SSH_SERVER_ALIVE_INTERVAL: int = 30
+# The default package repository for all components.
+FUCHSIA_PACKAGE_REPO_NAME = 'fuchsia.com'
+
+
+class SSHResult:
+    """Result of an SSH command."""
+
+    def __init__(
+        self, process: Union[subprocess.CompletedProcess,
+                             subprocess.CalledProcessError]
+    ) -> None:
+        self._raw_stdout = process.stdout
+        self._stdout = process.stdout.decode('utf-8', errors='replace')
+        self._stderr = process.stderr.decode('utf-8', errors='replace')
+        self._exit_status: int = process.returncode
+
+    def __str__(self):
+        if self.exit_status == 0:
+            return self.stdout
+        return f'status {self.exit_status}, stdout: "{self.stdout}", stderr: "{self.stderr}"'
+
+    @property
+    def stdout(self) -> str:
+        return self._stdout
+
+    @property
+    def stderr(self) -> str:
+        return self._stderr
+
+    @property
+    def exit_status(self) -> int:
+        return self._exit_status
+
+    @property
+    def raw_stdout(self) -> bytes:
+        return self._raw_stdout
+
+
+class FuchsiaSSHError(signals.TestError):
+    """A SSH command returned with a non-zero status code."""
+
+    def __init__(self, command: str, result: SSHResult):
+        super().__init__(
+            f'SSH command "{command}" unexpectedly returned {result}')
+        self.result = result
+
+
+class SSHTimeout(signals.TestError):
+    """A SSH command timed out."""
+
+    def __init__(self, err: subprocess.TimeoutExpired):
+        super().__init__(
+            f'SSH command "{err.cmd}" timed out after {err.timeout}s, '
+            f'stdout="{err.stdout}", stderr="{err.stderr}"')
+
+
+class FuchsiaSSHTransportError(signals.TestError):
+    """Failure to send an SSH command."""
+
+
+@dataclass
+class SSHConfig:
+    """SSH client config."""
+
+    # SSH flags. See ssh(1) for full details.
+    host_name: str
+    identity_file: str
+
+    ssh_binary: str = 'ssh'
+    config_file: str = '/dev/null'
+    port: int = 22
+    user: str = DEFAULT_SSH_USER
+
+    # SSH options. See ssh_config(5) for full details.
+    connect_timeout: int = DEFAULT_SSH_CONNECT_TIMEOUT_SEC
+    server_alive_interval: int = DEFAULT_SSH_SERVER_ALIVE_INTERVAL
+    strict_host_key_checking: bool = False
+    user_known_hosts_file: str = "/dev/null"
+    log_level: str = "ERROR"
+
+    def full_command(self, command: str, force_tty: bool = False) -> List[str]:
+        """Generate the complete command to execute command over SSH.
+
+        Args:
+            command: The command to run over SSH
+            force_tty: Force pseudo-terminal allocation. This can be used to
+                execute arbitrary screen-based programs on a remote machine,
+                which can be very useful, e.g. when implementing menu services.
+
+        Returns:
+            Arguments composing the complete call to SSH.
+        """
+        optional_flags = []
+        if force_tty:
+            # Multiple -t options force tty allocation, even if ssh has no local
+            # tty. This is necessary for launching ssh with subprocess without
+            # shell=True.
+            optional_flags.append('-tt')
+
+        return [
+            self.ssh_binary,
+            # SSH flags
+            '-i',
+            self.identity_file,
+            '-F',
+            self.config_file,
+            '-p',
+            str(self.port),
+            # SSH configuration options
+            '-o',
+            f'ConnectTimeout={self.connect_timeout}',
+            '-o',
+            f'ServerAliveInterval={self.server_alive_interval}',
+            '-o',
+            f'StrictHostKeyChecking={"yes" if self.strict_host_key_checking else "no"}',
+            '-o',
+            f'UserKnownHostsFile={self.user_known_hosts_file}',
+            '-o',
+            f'LogLevel={self.log_level}',
+        ] + optional_flags + [
+            f'{self.user}@{self.host_name}'
+        ] + command.split()
+
+
+class SSHProvider:
+    """Device-specific provider for SSH clients."""
+
+    def __init__(self, config: SSHConfig) -> None:
+        """
+        Args:
+            config: SSH client config
+        """
+        logger_tag = f"ssh | {config.host_name}"
+        if config.port != DEFAULT_SSH_PORT:
+            logger_tag += f':{config.port}'
+
+        # Check if the private key exists
+
+        self.log = logger.create_tagged_trace_logger(logger_tag)
+        self.config = config
+
+    def run(self,
+            command: str,
+            timeout_sec: int = DEFAULT_SSH_TIMEOUT_SEC,
+            connect_retries: int = 3,
+            force_tty: bool = False) -> SSHResult:
+        """Run a command on the device then exit.
+
+        Args:
+            command: String to send to the device.
+            timeout_sec: Seconds to wait for the command to complete.
+            connect_retries: Amount of times to retry connect on fail.
+            force_tty: Force pseudo-terminal allocation.
+
+        Raises:
+            FuchsiaSSHError: if the SSH command returns a non-zero status code
+            FuchsiaSSHTimeout: if there is no response within timeout_sec
+            FuchsiaSSHTransportError: if SSH fails to run the command
+
+        Returns:
+            SSHResults from the executed command.
+        """
+        err: Exception
+        for i in range(0, connect_retries):
+            try:
+                return self._run(command, timeout_sec, force_tty)
+            except FuchsiaSSHTransportError as e:
+                err = e
+                self.log.warn(f'Connect failed: {e}')
+        raise err
+
+    def _run(self, command: str, timeout_sec: int, force_tty: bool) -> SSHResult:
+        full_command = self.config.full_command(command, force_tty)
+        self.log.debug(f'Running "{" ".join(full_command)}"')
+        try:
+            process = subprocess.run(full_command,
+                                     capture_output=True,
+                                     timeout=timeout_sec,
+                                     check=True)
+        except subprocess.CalledProcessError as e:
+            if e.returncode == 255:
+                stderr = e.stderr.decode('utf-8', errors='replace')
+                if 'Name or service not known' in stderr or 'Host does not exist' in stderr:
+                    raise FuchsiaSSHTransportError(
+                        f'Hostname {self.config.host_name} cannot be resolved to an address'
+                    ) from e
+                if 'Connection timed out' in stderr:
+                    raise FuchsiaSSHTransportError(
+                        f'Failed to establish a connection to {self.config.host_name} within {timeout_sec}s'
+                    ) from e
+                if 'Connection refused' in stderr:
+                    raise FuchsiaSSHTransportError(
+                        f'Connection refused by {self.config.host_name}') from e
+
+            raise FuchsiaSSHError(command, SSHResult(e)) from e
+        except subprocess.TimeoutExpired as e:
+            raise SSHTimeout(e) from e
+
+        return SSHResult(process)
+
+    def start_v1_component(self,
+                           component: str,
+                           timeout_sec: int = 5,
+                           repo: str = FUCHSIA_PACKAGE_REPO_NAME) -> None:
+        """Start a CFv1 component in the background.
+
+        Args:
+            component: Name of the component without ".cmx".
+            timeout_sec: Seconds to wait for the process to show up in 'ps'.
+            repo: Default package repository for all components.
+
+        Raises:
+            TimeoutError: when the component doesn't launch within timeout_sec
+        """
+        # The "run -d" command will hang when executed without a pseudo-tty
+        # allocated.
+        self.run(
+            f'run -d fuchsia-pkg://{repo}/{component}#meta/{component}.cmx', force_tty=True)
+
+        timeout = time.perf_counter() + timeout_sec
+        while True:
+            ps_cmd = self.run("ps")
+            if f'{component}.cmx' in ps_cmd.stdout:
+                return
+            if time.perf_counter() > timeout:
+                raise TimeoutError(
+                    f'Failed to start "{component}.cmx" after {timeout_sec}s')
+
+    def stop_v1_component(self, component: str) -> None:
+        """Stop all instances of a CFv1 component.
+
+        Args:
+            component: Name of the component without ".cmx"
+        """
+        try:
+            self.run(f'killall {component}.cmx')
+        except FuchsiaSSHError as e:
+            if 'no tasks found' in e.result.stderr:
+                return
+            raise e
diff --git a/acts/framework/acts/controllers/fuchsia_lib/sysinfo_lib.py b/acts/framework/acts/controllers/fuchsia_lib/sysinfo_lib.py
deleted file mode 100644
index 239b2dc..0000000
--- a/acts/framework/acts/controllers/fuchsia_lib/sysinfo_lib.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python3
-#
-#   Copyright 2020 - 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.
-#   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.
-
-from acts.controllers.fuchsia_lib.base_lib import BaseLib
-
-
-class FuchsiaSysInfoLib(BaseLib):