summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/fuchsia/device_target.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/build/fuchsia/device_target.py')
-rw-r--r--third_party/libwebrtc/build/fuchsia/device_target.py266
1 files changed, 266 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/fuchsia/device_target.py b/third_party/libwebrtc/build/fuchsia/device_target.py
new file mode 100644
index 0000000000..6905a623dd
--- /dev/null
+++ b/third_party/libwebrtc/build/fuchsia/device_target.py
@@ -0,0 +1,266 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Implements commands for running and interacting with Fuchsia on devices."""
+
+import boot_data
+import logging
+import os
+import pkg_repo
+import re
+import subprocess
+import target
+import time
+
+from common import EnsurePathExists, GetHostToolPathFromPlatform
+
+# The maximum times to attempt mDNS resolution when connecting to a freshly
+# booted Fuchsia instance before aborting.
+BOOT_DISCOVERY_ATTEMPTS = 30
+
+# Number of failed connection attempts before redirecting system logs to stdout.
+CONNECT_RETRY_COUNT_BEFORE_LOGGING = 10
+
+# Number of seconds between each device discovery.
+BOOT_DISCOVERY_DELAY_SECS = 4
+
+# Time between a reboot command is issued and when connection attempts from the
+# host begin.
+_REBOOT_SLEEP_PERIOD = 20
+
+
+def GetTargetType():
+ return DeviceTarget
+
+
+class DeviceTarget(target.Target):
+ """Prepares a device to be used as a deployment target. Depending on the
+ command line parameters, it automatically handling a number of preparatory
+ steps relating to address resolution.
+
+ If |_node_name| is unset:
+ If there is one running device, use it for deployment and execution.
+
+ If there are more than one running devices, then abort and instruct the
+ user to re-run the command with |_node_name|
+
+ If |_node_name| is set:
+ If there is a running device with a matching nodename, then it is used
+ for deployment and execution.
+
+ If |_host| is set:
+ Deploy to a device at the host IP address as-is."""
+
+ def __init__(self,
+ out_dir,
+ target_cpu,
+ host=None,
+ node_name=None,
+ port=None,
+ ssh_config=None,
+ fuchsia_out_dir=None,
+ os_check='update',
+ system_log_file=None):
+ """out_dir: The directory which will contain the files that are
+ generated to support the deployment.
+ target_cpu: The CPU architecture of the deployment target. Can be
+ "x64" or "arm64".
+ host: The address of the deployment target device.
+ node_name: The node name of the deployment target device.
+ port: The port of the SSH service on the deployment target device.
+ ssh_config: The path to SSH configuration data.
+ fuchsia_out_dir: The path to a Fuchsia build output directory, for
+ deployments to devices paved with local Fuchsia builds.
+ os_check: If 'check', the target's SDK version must match.
+ If 'update', the target will be repaved if the SDK versions
+ mismatch.
+ If 'ignore', the target's SDK version is ignored."""
+
+ super(DeviceTarget, self).__init__(out_dir, target_cpu)
+
+ self._system_log_file = system_log_file
+ self._host = host
+ self._port = port
+ self._fuchsia_out_dir = None
+ self._node_name = node_name
+ self._os_check = os_check
+ self._pkg_repo = None
+
+ if self._host and self._node_name:
+ raise Exception('Only one of "--host" or "--name" can be specified.')
+
+ if fuchsia_out_dir:
+ if ssh_config:
+ raise Exception('Only one of "--fuchsia-out-dir" or "--ssh_config" can '
+ 'be specified.')
+
+ self._fuchsia_out_dir = os.path.expanduser(fuchsia_out_dir)
+ # Use SSH keys from the Fuchsia output directory.
+ self._ssh_config_path = os.path.join(self._fuchsia_out_dir, 'ssh-keys',
+ 'ssh_config')
+ self._os_check = 'ignore'
+
+ elif ssh_config:
+ # Use the SSH config provided via the commandline.
+ self._ssh_config_path = os.path.expanduser(ssh_config)
+
+ else:
+ # Default to using an automatically generated SSH config and keys.
+ boot_data.ProvisionSSH()
+ self._ssh_config_path = boot_data.GetSSHConfigPath()
+
+ @staticmethod
+ def CreateFromArgs(args):
+ return DeviceTarget(args.out_dir, args.target_cpu, args.host,
+ args.node_name, args.port, args.ssh_config,
+ args.fuchsia_out_dir, args.os_check,
+ args.system_log_file)
+
+ @staticmethod
+ def RegisterArgs(arg_parser):
+ device_args = arg_parser.add_argument_group(
+ 'device', 'External device deployment arguments')
+ device_args.add_argument('--host',
+ help='The IP of the target device. Optional.')
+ device_args.add_argument('--node-name',
+ help='The node-name of the device to boot or '
+ 'deploy to. Optional, will use the first '
+ 'discovered device if omitted.')
+ device_args.add_argument('--port',
+ '-p',
+ type=int,
+ default=None,
+ help='The port of the SSH service running on the '
+ 'device. Optional.')
+ device_args.add_argument('--ssh-config',
+ '-F',
+ help='The path to the SSH configuration used for '
+ 'connecting to the target device.')
+ device_args.add_argument(
+ '--os-check',
+ choices=['check', 'update', 'ignore'],
+ default='update',
+ help="Sets the OS version enforcement policy. If 'check', then the "
+ "deployment process will halt if the target\'s version doesn\'t "
+ "match. If 'update', then the target device will automatically "
+ "be repaved. If 'ignore', then the OS version won\'t be checked.")
+
+ def _ProvisionDeviceIfNecessary(self):
+ if self._Discover():
+ self._WaitUntilReady()
+ else:
+ raise Exception('Could not find device. If the device is connected '
+ 'to the host remotely, make sure that --host flag is '
+ 'set and that remote serving is set up.')
+
+ def _Discover(self):
+ """Queries mDNS for the IP address of a booted Fuchsia instance whose name
+ matches |_node_name| on the local area network. If |_node_name| isn't
+ specified, and there is only one device on the network, then returns the
+ IP address of that advice.
+
+ Sets |_host_name| and returns True if the device was found,
+ or waits up to |timeout| seconds and returns False if the device couldn't
+ be found."""
+
+ dev_finder_path = GetHostToolPathFromPlatform('device-finder')
+
+ if self._node_name:
+ command = [
+ dev_finder_path,
+ 'resolve',
+ '-device-limit',
+ '1', # Exit early as soon as a host is found.
+ self._node_name
+ ]
+ proc = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=open(os.devnull, 'w'))
+ else:
+ proc = self.RunFFXCommand(['target', 'list', '-f', 'simple'],
+ stdout=subprocess.PIPE,
+ stderr=open(os.devnull, 'w'))
+
+ output = set(proc.communicate()[0].strip().split('\n'))
+ if proc.returncode != 0:
+ return False
+
+ if self._node_name:
+ # Handle the result of "device-finder resolve".
+ self._host = output.pop().strip()
+ else:
+ name_host_pairs = [x.strip().split(' ') for x in output]
+
+ if len(name_host_pairs) > 1:
+ logging.info('More than one device was discovered on the network. '
+ 'Use --node-name <name> to specify the device to use.')
+ logging.info('List of devices:')
+ logging.info(output)
+ raise Exception('Ambiguous target device specification.')
+ assert len(name_host_pairs) == 1
+ # Check if device has both address and name.
+ if len(name_host_pairs[0]) < 2:
+ return False
+ self._host, self._node_name = name_host_pairs[0]
+
+ logging.info('Found device "%s" at address %s.' % (self._node_name,
+ self._host))
+
+ return True
+
+ def Start(self):
+ if self._host:
+ self._WaitUntilReady()
+ else:
+ self._ProvisionDeviceIfNecessary()
+
+ def GetPkgRepo(self):
+ if not self._pkg_repo:
+ if self._fuchsia_out_dir:
+ # Deploy to an already-booted device running a local Fuchsia build.
+ self._pkg_repo = pkg_repo.ExternalPkgRepo(
+ os.path.join(self._fuchsia_out_dir, 'amber-files'))
+ else:
+ # Create an ephemeral package repository, then start both "pm serve" as
+ # well as the bootserver.
+ self._pkg_repo = pkg_repo.ManagedPkgRepo(self)
+
+ return self._pkg_repo
+
+ def _ParseNodename(self, output):
+ # Parse the nodename from bootserver stdout.
+ m = re.search(r'.*Proceeding with nodename (?P<nodename>.*)$', output,
+ re.MULTILINE)
+ if not m:
+ raise Exception('Couldn\'t parse nodename from bootserver output.')
+ self._node_name = m.groupdict()['nodename']
+ logging.info('Booted device "%s".' % self._node_name)
+
+ # Repeatedly search for a device for |BOOT_DISCOVERY_ATTEMPT|
+ # number of attempts. If a device isn't found, wait
+ # |BOOT_DISCOVERY_DELAY_SECS| before searching again.
+ logging.info('Waiting for device to join network.')
+ for _ in xrange(BOOT_DISCOVERY_ATTEMPTS):
+ if self._Discover():
+ break
+ time.sleep(BOOT_DISCOVERY_DELAY_SECS)
+
+ if not self._host:
+ raise Exception('Device %s couldn\'t be discovered via mDNS.' %
+ self._node_name)
+
+ self._WaitUntilReady();
+
+ def _GetEndpoint(self):
+ return (self._host, self._port)
+
+ def _GetSshConfigPath(self):
+ return self._ssh_config_path
+
+ def Restart(self):
+ """Restart the device."""
+
+ self.RunCommandPiped('dm reboot')
+ time.sleep(_REBOOT_SLEEP_PERIOD)
+ self.Start()