140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
# 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.
|
|
|
|
import logging
|
|
import os
|
|
import platform
|
|
import signal
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import threading
|
|
|
|
DIR_SOURCE_ROOT = os.path.abspath(
|
|
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
|
|
IMAGES_ROOT = os.path.join(
|
|
DIR_SOURCE_ROOT, 'third_party', 'fuchsia-sdk', 'images')
|
|
SDK_ROOT = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'fuchsia-sdk', 'sdk')
|
|
|
|
def EnsurePathExists(path):
|
|
"""Checks that the file |path| exists on the filesystem and returns the path
|
|
if it does, raising an exception otherwise."""
|
|
|
|
if not os.path.exists(path):
|
|
raise IOError('Missing file: ' + path)
|
|
|
|
return path
|
|
|
|
def GetHostOsFromPlatform():
|
|
host_platform = sys.platform
|
|
if host_platform.startswith('linux'):
|
|
return 'linux'
|
|
elif host_platform.startswith('darwin'):
|
|
return 'mac'
|
|
raise Exception('Unsupported host platform: %s' % host_platform)
|
|
|
|
def GetHostArchFromPlatform():
|
|
host_arch = platform.machine()
|
|
if host_arch == 'x86_64':
|
|
return 'x64'
|
|
elif host_arch == 'aarch64':
|
|
return 'arm64'
|
|
raise Exception('Unsupported host architecture: %s' % host_arch)
|
|
|
|
def GetHostToolPathFromPlatform(tool):
|
|
host_arch = platform.machine()
|
|
return os.path.join(SDK_ROOT, 'tools', GetHostArchFromPlatform(), tool)
|
|
|
|
|
|
def GetEmuRootForPlatform(emulator):
|
|
return os.path.join(
|
|
DIR_SOURCE_ROOT, 'third_party', '{0}-{1}-{2}'.format(
|
|
emulator, GetHostOsFromPlatform(), GetHostArchFromPlatform()))
|
|
|
|
|
|
def ConnectPortForwardingTask(target, local_port, remote_port = 0):
|
|
"""Establishes a port forwarding SSH task to a localhost TCP endpoint hosted
|
|
at port |local_port|. Blocks until port forwarding is established.
|
|
|
|
Returns the remote port number."""
|
|
|
|
forwarding_flags = ['-O', 'forward', # Send SSH mux control signal.
|
|
'-R', '%d:localhost:%d' % (remote_port, local_port),
|
|
'-v', # Get forwarded port info from stderr.
|
|
'-NT'] # Don't execute command; don't allocate terminal.
|
|
|
|
if remote_port != 0:
|
|
# Forward to a known remote port.
|
|
task = target.RunCommand([], ssh_args=forwarding_flags)
|
|
if task.returncode != 0:
|
|
raise Exception('Could not establish a port forwarding connection.')
|
|
return
|
|
|
|
task = target.RunCommandPiped([],
|
|
ssh_args=forwarding_flags,
|
|
stdout=subprocess.PIPE,
|
|
stderr=open('/dev/null'))
|
|
output = task.stdout.readlines()
|
|
task.wait()
|
|
if task.returncode != 0:
|
|
raise Exception('Got an error code when requesting port forwarding: %d' %
|
|
task.returncode)
|
|
|
|
parsed_port = int(output[0].strip())
|
|
logging.debug('Port forwarding established (local=%d, device=%d)' %
|
|
(local_port, parsed_port))
|
|
return parsed_port
|
|
|
|
|
|
def GetAvailableTcpPort():
|
|
"""Finds a (probably) open port by opening and closing a listen socket."""
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.bind(("", 0))
|
|
port = sock.getsockname()[1]
|
|
sock.close()
|
|
return port
|
|
|
|
|
|
def SubprocessCallWithTimeout(command, silent=False, timeout_secs=None):
|
|
"""Helper function for running a command.
|
|
|
|
Args:
|
|
command: The command to run.
|
|
silent: If true, stdout and stderr of the command will not be printed.
|
|
timeout_secs: Maximum amount of time allowed for the command to finish.
|
|
|
|
Returns:
|
|
A tuple of (return code, stdout, stderr) of the command. Raises
|
|
an exception if the subprocess times out.
|
|
"""
|
|
|
|
if silent:
|
|
devnull = open(os.devnull, 'w')
|
|
process = subprocess.Popen(command, stdout=devnull, stderr=devnull)
|
|
else:
|
|
process = subprocess.Popen(command,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
timeout_timer = None
|
|
if timeout_secs:
|
|
|
|
def interrupt_process():
|
|
process.send_signal(signal.SIGKILL)
|
|
|
|
timeout_timer = threading.Timer(timeout_secs, interrupt_process)
|
|
|
|
# Ensure that keyboard interrupts are handled properly (crbug/1198113).
|
|
timeout_timer.daemon = True
|
|
|
|
timeout_timer.start()
|
|
|
|
out, err = process.communicate()
|
|
if timeout_timer:
|
|
timeout_timer.cancel()
|
|
|
|
if process.returncode == -9:
|
|
raise Exception('Timeout when executing \"%s\".' % ' '.join(command))
|
|
|
|
return process.returncode, out, err
|