Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35a39e2e authored by Jack He's avatar Jack He
Browse files

Cert: Wait for backing process to disconnect signal port

* So that we do not get into "Address already in use" error

Bug: 197895596
Tag: #gd-refactor
Test: gd/cert/run
Change-Id: I9ec11307dc7414ad047a5982b64cc20492dde080
parent 22b05a5e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -59,6 +59,9 @@ def setup_rootcanal(dut_module, cert_module, verbose_mode, log_path_base, contro
        info['make_rootcanal_ports_available'] = make_ports_available((rootcanal_test_port, rootcanal_hci_port,
                                                                       rootcanal_link_layer_port))
        if not make_ports_available((rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port)):
            logging.error(
                "Failed to free ports rootcanal_test_port={}, rootcanal_hci_port={}, rootcanal_link_layer_port={}".
                format(rootcanal_test_port, rootcanal_hci_port, rootcanal_link_layer_port))
            return info

        # Start root canal process
@@ -78,10 +81,12 @@ def setup_rootcanal(dut_module, cert_module, verbose_mode, log_path_base, contro
            info['is_rootcanal_process_started'] = True
        else:
            info['is_rootcanal_process_started'] = False
            logging.error("rootcanal process failed to start")
            return info
        info['is_subprocess_alive'] = is_subprocess_alive(rootcanal_process)
        if not is_subprocess_alive(rootcanal_process):
            info['is_subprocess_alive'] = False
            logging.error("rootcanal died after running")
            return info

        info['rootcanal_logger'] = AsyncSubprocessLogger(
+42 −8
Original line number Diff line number Diff line
@@ -15,17 +15,14 @@
#   limitations under the License.

from abc import ABC
from datetime import datetime
import inspect
import logging
import os
import pathlib
import selectors
import shutil
import signal
import socket
import subprocess
import time
from typing import List

import grpc

@@ -152,11 +149,14 @@ class GdDeviceBaseCore(ABC):
            # Setup signaling socket
            signal_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            signal_socket.bind(("localhost", self.signal_port))
            # Allow only one incoming connection
            signal_socket.listen(1)
            signal_socket.settimeout(300)  # 5 minute timeout for blocking socket operations
            # Set socket to non-blocking mode and use select() to block for timeout
            signal_socket.settimeout(0)
            signal_socket.setblocking(False)

            # Start backing process
            logging.debug("Running %s" % " ".join(self.cmd))
            logging.debug("[%s] Running %s %s" % (self.type_identifier, self.label, " ".join(self.cmd)))
            self.backing_process = subprocess.Popen(
                self.cmd,
                cwd=get_gd_root(),
@@ -165,14 +165,48 @@ class GdDeviceBaseCore(ABC):
                stderr=subprocess.STDOUT,
                universal_newlines=True)
            if not self.backing_process:
                logging.error("[%s] failed to open backing process for %s" % (self.type_identifier, self.label))
                return
            self.is_backing_process_alive = is_subprocess_alive(self.backing_process)
            if not self.is_backing_process_alive:
                return

            # Wait for process to be ready
            logging.debug("Waiting for backing_process accept.")
            signal_socket.accept()
            logging.debug("[%s] Waiting for %s backing_process accept at port %d" % (self.type_identifier, self.label,
                                                                                     self.signal_port))
            selector = selectors.DefaultSelector()
            selector.register(signal_socket, selectors.EVENT_READ)
            # 60 second timeout for backing process to connect to us
            timeout = 60
            ret = selector.select(timeout=timeout)
            selector.unregister(signal_socket)
            if not ret:
                logging.error("[{}] Failed to accept {} backing process connection in {} seconds".format(
                    self.type_identifier, self.label, timeout))
                signal_socket.shutdown(socket.SHUT_RDWR)
                return
            conn, addr = signal_socket.accept()
            conn.setblocking(False)
            with conn:
                logging.debug("[{}] Connected {} by {}".format(self.type_identifier, self.label, addr))
                selector.register(conn, selectors.EVENT_READ)
                # Give 10 seconds for remote to disconnect from us
                timeout = 10
                ret = selector.select(timeout=timeout)
                selector.unregister(conn)
                if not ret:
                    logging.warning("[{}] Failed to disconnect {} backing process in {} seconds".format(
                        self.type_identifier, self.label, timeout))
                else:
                    data = conn.recv(1024)
                    if data:
                        logging.warning("[{}] Received {} data {!r}, but not wanted".format(
                            self.type_identifier, self.label, data))
                    else:
                        logging.debug("[{}] Received EOF to disconnect from {}".format(
                            self.type_identifier, self.label))
                conn.shutdown(socket.SHUT_RDWR)
            signal_socket.shutdown(socket.SHUT_RDWR)

        self.backing_process_logger = AsyncSubprocessLogger(
            self.backing_process, [self.backing_process_log_path],