feat: add handle AdbError: unknown host service

This commit is contained in:
2026-07-06 22:40:36 +08:00
parent 63d238171f
commit 430d69695c
11 changed files with 104 additions and 26 deletions
+30 -6
View File
@@ -15,9 +15,9 @@ from module.base.decorator import Config, cached_property, del_cached_property,
from module.base.utils import SelectedGrids, ensure_time
from module.device.connection_attr import ConnectionAttr
from module.device.env import IS_LINUX, IS_MACINTOSH, IS_WINDOWS
from module.device.method.utils import (
PackageNotInstalled, RETRY_TRIES, get_serial_pair, handle_adb_error,
possible_reasons, random_port, recv_all, remove_shell_warning, retry_sleep)
from module.device.method.utils import (PackageNotInstalled, RETRY_TRIES, get_serial_pair, handle_adb_error,
handle_unknown_host_service, possible_reasons, random_port, recv_all,
remove_shell_warning, retry_sleep)
from module.exception import EmulatorNotRunningError, RequestHumanTakeover
from module.logger import logger
@@ -50,6 +50,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# Package not installed
@@ -142,8 +146,18 @@ class Connection(ConnectionAttr):
"""
cmd = list(map(str, cmd))
cmd = [self.adb_binary, '-s', self.serial] + cmd
logger.info(f'Execute: {cmd}')
return self.subprocess_run(cmd, timeout=timeout)
def subprocess_run(self, cmd, timeout=10):
"""
Args:
cmd (list):
timeout (int):
Returns:
str:
"""
logger.info(f'Execute: {cmd}')
# Use shell=True to disable console window when using GUI.
# Although, there's still a window when you stop running in GUI, which cause by gooey.
# To disable it, edit gooey/gui/util/taskkill.py
@@ -160,11 +174,21 @@ class Connection(ConnectionAttr):
@Config.when(DEVICE_OVER_HTTP=True)
def adb_command(self, cmd, timeout=10):
logger.warning(
f'adb_command() is not available when connecting over http: {self.serial}, '
logger.critical(
f'Trying to execute {cmd}, '
f'but adb_command() is not available when connecting over http: {self.serial}, '
)
raise RequestHumanTakeover
def adb_start_server(self):
"""
Use `adb devices` as `adb start-server`, result is actually useless
Start ADB using subprocess instead of connecting via socket to kill the other ADBs
"""
stdout = self.subprocess_run([self.adb_binary, 'devices'])
logger.info(stdout)
return stdout
@Config.when(DEVICE_OVER_HTTP=False)
def adb_shell(self, cmd, stream=False, recvall=True, timeout=10, rstrip=True):
"""
+5 -1
View File
@@ -10,7 +10,7 @@ from lxml import etree
from module.base.decorator import Config
from module.device.connection import Connection
from module.device.method.utils import (ImageTruncated, PackageNotInstalled, RETRY_TRIES, handle_adb_error,
remove_prefix, retry_sleep)
handle_unknown_host_service, remove_prefix, retry_sleep)
from module.exception import RequestHumanTakeover, ScriptError
from module.logger import logger
@@ -43,6 +43,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# Package not installed
+8 -3
View File
@@ -6,7 +6,8 @@ from adbutils.errors import AdbError
from module.base.utils import *
from module.device.connection import Connection
from module.device.method.utils import (ImageTruncated, RETRY_TRIES, handle_adb_error, retry_sleep)
from module.device.method.utils import (ImageTruncated, RETRY_TRIES, handle_adb_error, handle_unknown_host_service,
retry_sleep)
from module.exception import RequestHumanTakeover, ScriptError
from module.logger import logger
@@ -49,6 +50,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# ImageTruncated
@@ -164,11 +169,11 @@ class AScreenCap(Connection):
# ValueError: cannot reshape array of size 0 into shape (720,1280,4)
raise ImageTruncated(str(e))
image = cv2.flip(image, 0, dst=image)
cv2.flip(image, 0, dst=image)
if image is None:
raise ImageTruncated('Empty image after cv2.flip')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
if image is None:
raise ImageTruncated('Empty image after cv2.cvtColor')
+5 -1
View File
@@ -10,7 +10,7 @@ from module.base.decorator import cached_property, del_cached_property
from module.base.timer import Timer
from module.device.method.uiautomator_2 import ProcessInfo, Uiautomator2
from module.device.method.utils import (
ImageTruncated, PackageNotInstalled, RETRY_TRIES, handle_adb_error, retry_sleep)
ImageTruncated, PackageNotInstalled, RETRY_TRIES, handle_adb_error, handle_unknown_host_service, retry_sleep)
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -47,6 +47,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# Package not installed
+6 -2
View File
@@ -8,8 +8,8 @@ from module.base.decorator import cached_property
from module.base.timer import Timer
from module.base.utils import point2str, random_rectangle_point
from module.device.method.adb import Adb
from module.device.method.utils import (RETRY_TRIES, retry_sleep,
HierarchyButton, handle_adb_error)
from module.device.method.utils import (HierarchyButton, RETRY_TRIES, handle_adb_error, handle_unknown_host_service,
retry_sleep)
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -62,6 +62,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# HermitError: {"code":-1,"msg":"error"}
+6 -1
View File
@@ -9,7 +9,7 @@ from module.base.timer import Timer
from module.base.utils import *
from module.device.connection import Connection
from module.device.method.minitouch import CommandBuilder, insert_swipe
from module.device.method.utils import RETRY_TRIES, handle_adb_error, retry_sleep
from module.device.method.utils import RETRY_TRIES, handle_adb_error, handle_unknown_host_service, retry_sleep
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -51,6 +51,11 @@ def retry(func):
def init():
self.adb_reconnect()
del_cached_property(self, '_maatouch_builder')
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
del_cached_property(self, '_maatouch_builder')
else:
break
# MaaTouchNotInstalledError: Received "Aborted" from MaaTouch
+8 -1
View File
@@ -14,7 +14,7 @@ from module.base.decorator import Config, cached_property, del_cached_property,
from module.base.timer import Timer
from module.base.utils import *
from module.device.connection import Connection
from module.device.method.utils import RETRY_TRIES, handle_adb_error, retry_sleep
from module.device.method.utils import RETRY_TRIES, handle_adb_error, handle_unknown_host_service, retry_sleep
from module.exception import RequestHumanTakeover, ScriptError
from module.logger import logger
@@ -354,6 +354,13 @@ def retry(func):
if self._minitouch_port:
self.adb_forward_remove(f'tcp:{self._minitouch_port}')
del_cached_property(self, '_minitouch_builder')
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
if self._minitouch_port:
self.adb_forward_remove(f'tcp:{self._minitouch_port}')
del_cached_property(self, '_minitouch_builder')
else:
break
except BrokenPipeError as e:
+5 -1
View File
@@ -10,7 +10,7 @@ from module.base.utils import random_rectangle_point
from module.device.method.minitouch import insert_swipe
from module.device.method.scrcpy.core import ScrcpyCore, ScrcpyError
from module.device.method.uiautomator_2 import Uiautomator2
from module.device.method.utils import RETRY_TRIES, handle_adb_error, retry_sleep
from module.device.method.utils import RETRY_TRIES, handle_adb_error, handle_unknown_host_service, retry_sleep
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -62,6 +62,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# Unknown, probably a trucked image
+6 -2
View File
@@ -10,7 +10,7 @@ from lxml import etree
from module.base.utils import *
from module.device.connection import Connection
from module.device.method.utils import (ImageTruncated, PackageNotInstalled, RETRY_TRIES, handle_adb_error,
possible_reasons, retry_sleep)
handle_unknown_host_service, possible_reasons, retry_sleep)
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -50,6 +50,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# RuntimeError: USB device 127.0.0.1:5555 is offline
@@ -121,7 +125,7 @@ class Uiautomator2(Connection):
if image is None:
raise ImageTruncated('Empty image after cv2.imdecode')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
if image is None:
raise ImageTruncated('Empty image after cv2.cvtColor')
+19 -6
View File
@@ -238,12 +238,6 @@ def handle_adb_error(e):
# Raised by uiautomator2 when current adb service is killed by another version of adb service.
logger.error(e)
return True
elif 'unknown host service' in text:
# AdbError(unknown host service)
# Another version of ADB service started, current ADB service has been killed.
# Usually because user opened a Chinese emulator, which uses ADB from the Stone Age.
logger.error(e)
return True
else:
# AdbError()
logger.exception(e)
@@ -255,6 +249,25 @@ def handle_adb_error(e):
return False
def handle_unknown_host_service(e):
"""
Args:
e (Exception):
Returns:
bool: If should retry
"""
text = str(e)
if 'unknown host service' in text:
# AdbError(unknown host service)
# Another version of ADB service started, current ADB service has been killed.
# Usually because user opened a Chinese emulator, which uses ADB from the Stone Age.
logger.error(e)
return True
else:
return False
def get_serial_pair(serial):
"""
Args:
+6 -2
View File
@@ -4,8 +4,8 @@ from functools import wraps
from adbutils.errors import AdbError
from module.device.connection import Connection
from module.device.method.utils import (RETRY_TRIES, retry_sleep,
handle_adb_error, PackageNotInstalled)
from module.device.method.utils import (PackageNotInstalled, RETRY_TRIES, handle_adb_error, handle_unknown_host_service,
retry_sleep)
from module.exception import RequestHumanTakeover
from module.logger import logger
@@ -38,6 +38,10 @@ def retry(func):
if handle_adb_error(e):
def init():
self.adb_reconnect()
elif handle_unknown_host_service(e):
def init():
self.adb_start_server()
self.adb_reconnect()
else:
break
# Package not installed