Allow nearby share tests to be run with Skylab Android support.

BUG=b:226934630
TEST=test_that localhost:2222 --args="phone_station=localhost phone_station_ssh_port=2222 android_serial=8CTX1T5T8" tast.cross-device-android.local
TEST=test_that localhost:2222 --args="phone_station=localhost phone_station_ssh_port=2222 android_serial=8CTX1T5T8" tast.nearby-share--android.local

Change-Id: Icaa1630b847a49dade4c0a2e1ca5eb4bf523f7fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/3603072
Reviewed-by: Garry Wang <[email protected]>
Tested-by: David Haddock <[email protected]>
Reviewed-by: Derek Beckett <[email protected]>
diff --git a/server/hosts/android_host.py b/server/hosts/android_host.py
index 13de1f5..ace1568 100644
--- a/server/hosts/android_host.py
+++ b/server/hosts/android_host.py
@@ -92,14 +92,23 @@
                     'Failed to initialize Android host due to'
                     ' serial_number is not found in host_info_store.')
 
-    def adb_over_tcp(self, port=5555):
+    def adb_over_tcp(self, port=5555, persist_reboot=False):
         """Restart adb server listening on a TCP port.
 
         Args:
             port: Tcp port for adb server to listening on, default value
                   is 5555 which is the default TCP/IP port for adb.
+            persist_reboot: True for adb over tcp to continue listening
+                            after the device reboots.
         """
-        self.run_adb_command('tcpip %s' % str(port))
+        port = str(port)
+        if persist_reboot:
+            self.run_adb_command('shell setprop persist.adb.tcp.port %s' %
+                                 port)
+            self.run_adb_command('shell setprop ctl.restart adbd')
+            self.wait_for_transport_state()
+
+        self.run_adb_command('tcpip %s' % port)
         self.adb_tcp_mode = True
 
     def cache_usb_dev_path(self):
@@ -171,6 +180,17 @@
             command = 'adb -s %s %s' % (self.serial_number, adb_command)
         return self.phone_station.run(command, ignore_status=ignore_status)
 
+    def wait_for_transport_state(self, transport='usb', state='device'):
+        """
+        Wait for a device to reach a desired state.
+
+        Args:
+            transport: usb, local, any
+            state: device, recovery, sideload, bootloader
+
+        """
+        self.run_adb_command('wait-for-%s-%s' % (transport, state))
+
     def start_adb_server(self):
         """Start adb server from the phone station."""
         # Adb home is created upon CrOS login, however on labstation we
@@ -186,7 +206,7 @@
         """Stop adb server from the phone station."""
         self.phone_station.run("adb kill-server")
 
-    def setup_for_cross_device_tests(self):
+    def setup_for_cross_device_tests(self, adb_persist_reboot=False):
         """
         Setup the Android phone for Cross Device tests.
 
@@ -205,7 +225,7 @@
         self.cache_usb_dev_path()
         self.ensure_device_connectivity()
         ip_address = self.get_wifi_ip_address()
-        self.adb_over_tcp()
+        self.adb_over_tcp(persist_reboot=adb_persist_reboot)
         return ip_address
 
     def close(self):
diff --git a/server/site_tests/tast/control.cross-device-android b/server/site_tests/tast/control.cross-device-android
index 31bc2f8..4639961 100644
--- a/server/site_tests/tast/control.cross-device-android
+++ b/server/site_tests/tast/control.cross-device-android
@@ -32,7 +32,7 @@
     ip_address = phone.setup_for_cross_device_tests()
 
     # Pass the phones adb-over-tcp "serial" (e.g 192.168.0.30:5555) to Tast as a global var.
-    ip_address_arg = 'crossdevice.phoneIP=%s:5555' % ip_address
+    ip_address_arg = 'crossdevice.PhoneIP=%s:5555' % ip_address
 
     job.run_test('tast',
                  host=host,
diff --git a/server/site_tests/tast/control.cross-device-android.local b/server/site_tests/tast/control.cross-device-android.local
index eb7a5f2..ab2be15 100644
--- a/server/site_tests/tast/control.cross-device-android.local
+++ b/server/site_tests/tast/control.cross-device-android.local
@@ -50,7 +50,7 @@
     ip_address = phone.setup_for_cross_device_tests()
 
     # Pass the phones adb-over-tcp "serial" (e.g 192.168.0.30:5555) to Tast as a global var.
-    ip_address_arg = 'crossdevice.phoneIP=%s:5555' % ip_address
+    ip_address_arg = 'crossdevice.PhoneIP=%s:5555' % ip_address
 
     job.run_test('tast',
                  host=host,
diff --git a/server/site_tests/tast/control.nearby-share-android b/server/site_tests/tast/control.nearby-share-android
new file mode 100644
index 0000000..d2c1b22
--- /dev/null
+++ b/server/site_tests/tast/control.nearby-share-android
@@ -0,0 +1,43 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = 'ChromeOS SW Engprod Team ([email protected])'
+NAME = 'tast.nearby-share-android'
+TIME = 'MEDIUM'
+TEST_TYPE = 'Server'
+ATTRIBUTES = 'suite:nearby-share-android'
+MAX_RESULT_SIZE_KB = 1024 * 1024
+PY_VERSION = 3
+
+# tast.py uses binaries installed from autotest_server_package.tar.bz2.
+REQUIRE_SSP = True
+
+DOC = '''Run the Tast Nearby Share test suite.'''
+
+from autotest_lib.server.cros.crossdevice import cross_device_util
+
+def run(machine):
+    # Wifi details that chromebook will connect to.
+    ssid = 'nearbysharing_1'
+    password = 'password'
+
+    # Get host objects for each device.
+    host = hosts.create_host(machine)
+    companions = hosts.create_companion_hosts(companion_hosts)
+    phone = companions[0]
+
+    # Configure devices for crossdevice tests.
+    cross_device_util.connect_to_wifi(host, ssid, password)
+    ip_address = phone.setup_for_cross_device_tests(adb_persist_reboot=True)
+
+    # Pass the phones adb-over-tcp "serial" (e.g 192.168.0.30:5555) to Tast as a global var.
+    ip_address_arg = 'crossdevice.PhoneIP=%s:5555' % ip_address
+
+    job.run_test('tast',
+                 host=host,
+                 test_exprs=['("group:nearby-share")'],
+                 ignore_test_failures=True, max_run_sec=10800,
+                 command_args=args,
+                 varslist=[ip_address_arg])
+parallel_simple(run, machines)
diff --git a/server/site_tests/tast/control.nearby-share-android.local b/server/site_tests/tast/control.nearby-share-android.local
new file mode 100644
index 0000000..db028b2
--- /dev/null
+++ b/server/site_tests/tast/control.nearby-share-android.local
@@ -0,0 +1,63 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = 'ChromeOS SW Engprod Team ([email protected])'
+NAME = 'tast.nearby-share-android.local'
+TIME = 'MEDIUM'
+TEST_TYPE = 'Server'
+MAX_RESULT_SIZE_KB = 1024 * 1024
+PY_VERSION = 3
+
+# tast.py uses binaries installed from autotest_server_package.tar.bz2.
+REQUIRE_SSP = True
+
+DOC = '''Run the Tast Nearby Share test suite with Skylab's Android support locally.
+
+This control file will setup the chromebook and android phone for you if you want to run locally.
+Locally means kicking off via test_that to run against either:
+1. One of the scheduling units / RF boxes in the lab.
+2. At your desk when using the chromebook as a fake labstation.
+You can use #2 to test the e2e adb-over-wifi flow without having a labstation at home.
+NOTE: Labstations store their adb keys at /var/lib/android_keys (and this gets wiped during login) so you need to click accept manually for the setups adb connection.
+
+You need to specify the wifi network details below that the chromebook and phone should be on together.
+Set <SET NETWORK NAME> to your SSID and <SET PASSWORD> to your network password.
+
+These args are expected to be passed to test_that:
+--args="phone_station=$PHONE_HOST android_serial=$ANDROID_SERIAL_NUMBER"
+
+When using port forwarding to locahost, the expected args are:
+--args="phone_station=locahost android_station_ssh_port=$FORWARDED_PORT android_serial=$ANDROID_SERIAL_NUMBER"
+$FORWARDED_PORT is the port of the labstation that you port forwarded to localhost
+
+'''
+
+from autotest_lib.server import utils
+from autotest_lib.server.cros.crossdevice import cross_device_util
+
+def run(machine):
+    # Wifi details that chromebook will connect to.
+    ssid = '<SET NETWORK NAME>'
+    password = '<SET PASSWORD>'
+
+    # Get host objects for each device.
+    host = hosts.create_host(machine)
+    args_dict = utils.args_to_dict(args)
+    android_args = hosts.AndroidHost.get_android_arguments(args_dict)
+    phone = hosts.AndroidHost('local_phone', android_args=android_args)
+
+    # Configure devices for crossdevice tests.
+    cross_device_util.connect_to_wifi(host, ssid, password)
+    ip_address = phone.setup_for_cross_device_tests(adb_persist_reboot=True)
+
+    # Pass the phones adb-over-tcp "serial" (e.g 192.168.0.30:5555) to Tast as a global var.
+    ip_address_arg = 'crossdevice.PhoneIP=%s:5555' % ip_address
+
+    job.run_test('tast',
+                 host=host,
+                 test_exprs=['("group:nearby-share")'],
+                 ignore_test_failures=True, max_run_sec=10800,
+                 command_args=args,
+                 varslist=[ip_address_arg])
+parallel_simple(run, machines)
diff --git a/site_utils/attribute_allowlist.txt b/site_utils/attribute_allowlist.txt
index b70330e..907c474 100644
--- a/site_utils/attribute_allowlist.txt
+++ b/site_utils/attribute_allowlist.txt
@@ -257,6 +257,7 @@
 suite:mtp
 suite:nbr
 suite:nearby-share
+suite:nearby-share-android
 suite:nearby-share-arc
 suite:nearby-share-dev
 suite:nearby-share-prod
diff --git a/test_suites/control.nearby-share-android b/test_suites/control.nearby-share-android
new file mode 100644
index 0000000..7f07c20
--- /dev/null
+++ b/test_suites/control.nearby-share-android
@@ -0,0 +1,20 @@
+# Copyright 2022 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+AUTHOR = "ChromeOS SW Engprod Team ([email protected])"
+NAME = "nearby-share-android"
+PURPOSE = "Suite to run Nearby Share tests on Chrome OS devices."
+TIME = "SHORT"
+TEST_CATEGORY = "General"
+TEST_CLASS = "suite"
+TEST_TYPE = "Server"
+DOC = """ This suite runs Cross Device tests. """
+
+import common
+from autotest_lib.server.cros.dynamic_suite import dynamic_suite
+args_dict['max_runtime_mins'] = 60
+args_dict['name'] = NAME
+args_dict['job'] = job
+dynamic_suite.reimage_and_run(**args_dict)
+