diff --git a/airtest/core/android/adb.py b/airtest/core/android/adb.py index 5bcafa85..09539d4a 100644 --- a/airtest/core/android/adb.py +++ b/airtest/core/android/adb.py @@ -38,7 +38,6 @@ def __init__(self, serialno=None, adb_path=None, server_addr=None): self._display_info_lock = threading.Lock() self._forward_local_using = [] self.__class__._instances.append(self) - # reg_cleanup(self._cleanup_forwards) @staticmethod def builtin_adb_path(): @@ -85,6 +84,16 @@ def start_server(self): """ return self.cmd("start-server", device=False) + def kill_server(self): + """ + Perform `adb kill-server` command to kill the adb server + + Returns: + None + + """ + return self.cmd("kill-server", device=False) + def version(self): """ Perform `adb version` command and return the command output @@ -690,8 +699,10 @@ def _cleanup_forwards(self): Returns: None """ - for local in self._forward_local_using[:]: - self.remove_forward(local) + for local in self._forward_local_using: + self.start_cmd(["forward", "--remove", local]) + + self._forward_local_using = [] @property def line_breaker(self): @@ -703,16 +714,10 @@ def line_breaker(self): """ if not self._line_breaker: - if platform.system() == "Windows": - if self.sdk_version >= SDK_VERISON_NEW: - line_breaker = b"\r\n" - else: - line_breaker = b"\r\r\n" + if self.sdk_version >= SDK_VERISON_NEW: + line_breaker = os.linesep else: - if self.sdk_version >= SDK_VERISON_NEW: - line_breaker = b"\n" - else: - line_breaker = b"\r\n" + line_breaker = b'\r' + os.linesep self._line_breaker = line_breaker return self._line_breaker @@ -1235,4 +1240,4 @@ def cleanup_adb_forward(): adb._cleanup_forwards() -reg_cleanup(cleanup_adb_forward) \ No newline at end of file +reg_cleanup(cleanup_adb_forward) diff --git a/airtest/core/android/javacap.py b/airtest/core/android/javacap.py index 8f3dd6d5..f51455e4 100644 --- a/airtest/core/android/javacap.py +++ b/airtest/core/android/javacap.py @@ -2,7 +2,7 @@ from airtest.utils.logger import get_logger from airtest.utils.safesocket import SafeSocket from airtest.utils.nbsp import NonBlockingStreamReader -from airtest.utils.snippet import reg_cleanup, on_method_ready +from airtest.utils.snippet import on_method_ready from airtest.core.android.yosemite import Yosemite import struct LOGGING = get_logger(__name__) @@ -20,7 +20,6 @@ class Javacap(Yosemite): def __init__(self, adb): super(Javacap, self).__init__(adb) self.frame_gen = None - reg_cleanup(self.teardown_stream) @on_method_ready('install_or_upgrade') def _setup_stream_server(self): diff --git a/airtest/core/android/minicap.py b/airtest/core/android/minicap.py index 4f92d1d9..e5f37779 100644 --- a/airtest/core/android/minicap.py +++ b/airtest/core/android/minicap.py @@ -35,7 +35,6 @@ def __init__(self, adb, projection=None): self.frame_gen = None self.stream_lock = threading.Lock() self.quirk_flag = 0 - reg_cleanup(self.teardown_stream) @ready_method def install_or_upgrade(self): @@ -260,6 +259,7 @@ def _setup_stream_server(self, lazy=False): # minicap server setup error, may be already setup by others # subprocess exit immediately raise RuntimeError("minicap server quit immediately") + reg_cleanup(proc.kill) return proc, nbsp, localport def get_frame_from_stream(self): diff --git a/airtest/core/android/minitouch.py b/airtest/core/android/minitouch.py index 8bf69f30..a03d7e93 100644 --- a/airtest/core/android/minitouch.py +++ b/airtest/core/android/minitouch.py @@ -145,8 +145,8 @@ def setup_server(self): # server setup error, may be already setup by others # subprocess exit immediately raise RuntimeError("minitouch server quit immediately") - reg_cleanup(p.kill) self.server_proc = p + # reg_cleanup(self.server_proc.kill) return p @on_method_ready('install_and_setup') @@ -378,7 +378,7 @@ def setup_client_backend(self): self.backend_stop_event = threading.Event() self.setup_client() t = threading.Thread(target=self._backend_worker, name="minitouch") - t.daemon = True + # t.daemon = True t.start() self.backend_thread = t self.handle = self.backend_queue.put diff --git a/airtest/core/android/rotation.py b/airtest/core/android/rotation.py index c102f8d3..2efcf5a4 100644 --- a/airtest/core/android/rotation.py +++ b/airtest/core/android/rotation.py @@ -18,6 +18,7 @@ def __init__(self, adb): self.ow_proc = None self.ow_callback = [] self._t = None + reg_cleanup(self.teardown) @on_method_ready('start') def get_ready(self): @@ -43,7 +44,11 @@ def _install_and_setup(self): if p.poll() is not None: raise RuntimeError("orientationWatcher setup error") self.ow_proc = p - reg_cleanup(self.ow_proc.kill) + # reg_cleanup(self.ow_proc.kill) + + def teardown(self): + if self.ow_proc: + self.ow_proc.kill() def start(self): """ @@ -60,6 +65,8 @@ def _refresh_by_ow(): if line == b"": if LOGGING is not None: # may be None atexit LOGGING.error("orientationWatcher has ended") + else: + print("orientationWatcher has ended") return None ori = int(line) / 90 @@ -81,7 +88,7 @@ def _run(): traceback.print_exc() self._t = threading.Thread(target=_run, name="rotationwatcher") - self._t.daemon = True + # self._t.daemon = True self._t.start() def reg_callback(self, ow_callback): diff --git a/airtest/core/ios/minicap.py b/airtest/core/ios/minicap.py index 4cce5742..d202b12b 100644 --- a/airtest/core/ios/minicap.py +++ b/airtest/core/ios/minicap.py @@ -7,7 +7,6 @@ from airtest.utils.logger import get_logger from airtest.utils.nbsp import NonBlockingStreamReader from airtest.utils.safesocket import SafeSocket -from airtest.utils.snippet import reg_cleanup LOGGING = get_logger(__name__) @@ -28,9 +27,7 @@ def __init__(self, udid=None, port=12345): def setup(self): cmd = [self.executable, "--udid", self.udid, "--port", str(self.port), "--resolution", self.resolution] - print(cmd) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) - reg_cleanup(proc.kill) nbsp = NonBlockingStreamReader(proc.stdout, print_output=True, name="minicap_sever") while True: line = nbsp.readline(timeout=10.0) diff --git a/airtest/core/win/screen.py b/airtest/core/win/screen.py index ee605b82..0c6b11e2 100644 --- a/airtest/core/win/screen.py +++ b/airtest/core/win/screen.py @@ -3,7 +3,7 @@ import win32api import win32ui import win32con -from airtest.aircv.utils import Image, pil_2_cv2 +from aircv.utils import Image, pil_2_cv2 SM_XVIRTUALSCREEN = 76 diff --git a/airtest/utils/nbsp.py b/airtest/utils/nbsp.py index 1c56bee1..0edc135b 100644 --- a/airtest/utils/nbsp.py +++ b/airtest/utils/nbsp.py @@ -40,7 +40,7 @@ def _populateQueue(stream, queue, kill_event): elif raise_EOF: raise UnexpectedEndOfStream else: - LOGGING.debug("EndOfStream") + print("EndOfStream: %s" % self.name) break self._kill_event = Event() diff --git a/airtest/utils/snippet.py b/airtest/utils/snippet.py index fe99b43d..0260900d 100644 --- a/airtest/utils/snippet.py +++ b/airtest/utils/snippet.py @@ -2,7 +2,7 @@ import atexit import sys from functools import wraps -from .compat import str_class +from .compat import str_class, queue def split_cmd(cmds): @@ -38,6 +38,10 @@ def get_std_encoding(stream): return getattr(stream, "encoding", None) or sys.getfilesystemencoding() + +CLEANUP_CALLS = queue.Queue() + + def reg_cleanup(func, *args, **kwargs): """ Clean the register for given function @@ -51,7 +55,37 @@ def reg_cleanup(func, *args, **kwargs): None """ - atexit.register(func, *args, **kwargs) + CLEANUP_CALLS.put((func, args, kwargs)) + # atexit.register(func, *args, **kwargs) + + +def _cleanup(): + # cleanup together to prevent atexit thread issue + while not CLEANUP_CALLS.empty(): + (func, args, kwargs) = CLEANUP_CALLS.get() + func(*args, **kwargs) + + +# atexit.register(_cleanup) + +import threading + + +_shutdown = threading._shutdown + + +def exitfunc(): + print("exiting.......") + _cleanup() + _shutdown() + + +# use threading._shutdown to exec cleanup when main thread exit +# atexit exec after all thread exit, which needs to cooperate with daemon thread. +# daemon thread is evil, which abruptly exit causing unexpected error +threading._shutdown = exitfunc + + def on_method_ready(method_name):