def _setup_target(self, build_path, build_ids_path, ports_to_forward, results_directory): # Tell SSH to forward all server ports from the Fuchsia device to # the host. forwarding_flags = [ '-O', 'forward', # Send SSH mux control signal. '-N', # Don't execute command '-T' # Don't allocate terminal. ] for port in ports_to_forward: forwarding_flags += ['-R', '%d:localhost:%d' % (port, port)] self._proxy = self._target.RunCommandPiped([], ssh_args=forwarding_flags, stderr=subprocess.PIPE) self._listener = self._target.RunCommandPiped(['log_listener'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) listener_log_path = os.path.join(results_directory, 'system.log') listener_log = open(listener_log_path, 'w') self.symbolizer = symbolizer.RunSymbolizer(self._listener.stdout, listener_log, [build_ids_path]) package_path = os.path.join(build_path, CONTENT_SHELL_PACKAGE_PATH) self._target.InstallPackage([package_path]) # Process will be forked for each worker, which may make QemuTarget # unusable (e.g. waitpid() for qemu process returns ECHILD after # fork() ). Save command runner before fork()ing, to use it later to # connect to the target. self.target_command_runner = self._target.GetCommandRunner()
def _start(self): if self._proc: raise ValueError('%s already running' % self._name) self._reset() # Fuchsia doesn't support stdin stream for packaged applications, so the # stdin stream for content_shell is routed through a separate TCP # socket. Open a local socket and then pass the address with the port as # --stdin-redirect parameter. content_shell will connect to this address # and will use that connection as its stdin stream. listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.bind(('127.0.0.1', 0)) listen_socket.listen(1) stdin_port = listen_socket.getsockname()[1] command = ['%s=%s' % (k, v) for k, v in self._env.items()] + \ self._cmd + \ ['--no-sandbox', '--stdin-redirect=%s:%s' % (qemu_target.HOST_IP_ADDRESS, stdin_port)] proc = self._port.get_target_host().run_command(command) # Wait for incoming connection from content_shell. fd = listen_socket.fileno() read_fds, _, _ = select.select([fd], [], [], PROCESS_START_TIMEOUT) if fd not in read_fds: listen_socket.close() proc.kill() raise driver.DeviceFailure( 'Timed out waiting connection from content_shell.') # Python's interfaces for sockets and pipes are different. To masquerade # the socket as a pipe dup() the file descriptor and pass it to # os.fdopen(). stdin_socket, _ = listen_socket.accept() fd = stdin_socket.fileno() # pylint: disable=no-member stdin_pipe = os.fdopen(os.dup(fd), "w", 0) stdin_socket.close() proc.stdin.close() proc.stdin = stdin_pipe # Run symbolizer to filter the stderr stream. self._symbolizer_proc = symbolizer.RunSymbolizer( proc.stderr, [self._port.get_build_ids_path()]) proc.stderr = self._symbolizer_proc.stdout self._set_proc(proc)