优化杀死iproxy逻辑
This commit is contained in:
@@ -4,12 +4,12 @@ import signal
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
import wda
|
||||
import threading
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional
|
||||
import threading
|
||||
import subprocess
|
||||
|
||||
import wda
|
||||
from tidevice import Usbmux, ConnectionType
|
||||
from tidevice._device import BaseDevice
|
||||
from Entity.DeviceModel import DeviceModel
|
||||
@@ -23,10 +23,8 @@ class Deviceinfo(object):
|
||||
"""设备生命周期管理:以 deviceModelList 为唯一真理源"""
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
# ✅ 新增:连接线程池(最大 6 并发)
|
||||
# ✅ 连接线程池(最大 6 并发)
|
||||
self._connect_pool = ThreadPoolExecutor(max_workers=6)
|
||||
...
|
||||
|
||||
if os.name == "nt":
|
||||
self._si = subprocess.STARTUPINFO()
|
||||
@@ -44,11 +42,14 @@ class Deviceinfo(object):
|
||||
|
||||
self._lock = threading.Lock()
|
||||
self._model_index: Dict[str, DeviceModel] = {} # udid -> model
|
||||
# ✅ 1. 失踪时间戳记录(替代原来的 miss_count)
|
||||
# ✅ 失踪时间戳记录(替代原来的 miss_count)
|
||||
self._last_seen: Dict[str, float] = {}
|
||||
self._port_pool: List[int] = []
|
||||
self._port_in_use: set[int] = set()
|
||||
|
||||
# ✅ 新增:全局 iproxy 进程注册表 udid -> Popen
|
||||
self._iproxy_registry: Dict[str, subprocess.Popen] = {}
|
||||
|
||||
# region iproxy 初始化(原逻辑不变)
|
||||
try:
|
||||
self.iproxy_path = self._iproxy_path()
|
||||
@@ -76,6 +77,9 @@ class Deviceinfo(object):
|
||||
args = [str(self.iproxy_path), "-u", udid, str(local_port), str(remote_port)]
|
||||
p = subprocess.Popen(args, **self._popen_kwargs)
|
||||
|
||||
# ✅ 注册到全局表
|
||||
self._iproxy_registry[udid] = p
|
||||
|
||||
def _pipe_to_log(name: str, stream):
|
||||
try:
|
||||
for line in iter(stream.readline, ''):
|
||||
@@ -127,6 +131,13 @@ class Deviceinfo(object):
|
||||
for udid in need_remove:
|
||||
self._remove_model(udid)
|
||||
|
||||
# ✅ 实时清理孤儿 iproxy(原 10 秒改为每次循环)
|
||||
self._cleanup_orphan_iproxy()
|
||||
|
||||
# ✅ 设备全空时核平所有 iproxy
|
||||
if not self.deviceModelList:
|
||||
self._kill_all_iproxy()
|
||||
|
||||
# 2. 发现新设备 → 并发连接
|
||||
with self._lock:
|
||||
new_udids = [d.udid for d in lists
|
||||
@@ -146,7 +157,7 @@ class Deviceinfo(object):
|
||||
time.sleep(1)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# ✅ 3. USB 层枚举 SN(跨平台)
|
||||
# ✅ USB 层枚举 SN(跨平台)
|
||||
# ------------------------------------------------------------------
|
||||
def _usb_enumerate_sn(self) -> set[str]:
|
||||
try:
|
||||
@@ -155,7 +166,32 @@ class Deviceinfo(object):
|
||||
except Exception:
|
||||
return set()
|
||||
|
||||
# ===================== 以下代码与原文件完全一致 =====================
|
||||
# ----------------------------------------------------------
|
||||
# ✅ 清理孤儿 iproxy
|
||||
# ----------------------------------------------------------
|
||||
def _cleanup_orphan_iproxy(self):
|
||||
live_udids = set(self._model_index.keys())
|
||||
for udid, proc in list(self._iproxy_registry.items()):
|
||||
if udid not in live_udids:
|
||||
LogManager.warning(f"发现孤儿 iproxy 进程,UDID 不在线:{udid},正在清理")
|
||||
self._terminate_proc(proc)
|
||||
self._iproxy_registry.pop(udid, None)
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# ✅ 核平所有 iproxy(Windows / macOS 通用)
|
||||
# ----------------------------------------------------------
|
||||
def _kill_all_iproxy(self):
|
||||
try:
|
||||
if os.name == "nt":
|
||||
subprocess.run(["taskkill", "/F", "/IM", "iproxy.exe"], check=False)
|
||||
else:
|
||||
subprocess.run(["pkill", "-f", "iproxy"], check=False)
|
||||
self._iproxy_registry.clear()
|
||||
LogManager.info("已强制清理所有 iproxy 进程")
|
||||
except Exception as e:
|
||||
LogManager.warning(f"强制清理 iproxy 失败:{e}")
|
||||
|
||||
# -------------------- 以下代码与原文件完全一致 --------------------
|
||||
def _wda_health_checker(self):
|
||||
while True:
|
||||
time.sleep(1)
|
||||
@@ -229,6 +265,11 @@ class Deviceinfo(object):
|
||||
print(f"【删】待杀进程数 count={len(to_kill)} udid={udid}")
|
||||
LogManager.method_info(f"【删】待杀进程数 count={len(to_kill)} udid={udid}", method="device_count")
|
||||
|
||||
# ✅ 先清理注册表中的 iproxy
|
||||
iproxy_proc = self._iproxy_registry.pop(udid, None)
|
||||
if iproxy_proc:
|
||||
self._terminate_proc(iproxy_proc)
|
||||
|
||||
for idx, item in enumerate(to_kill, 1):
|
||||
print(f"【删】杀进程 {idx}/{len(to_kill)} pid={item.get('target').pid} udid={udid}")
|
||||
LogManager.method_info(f"【删】杀进程 {idx}/{len(to_kill)} pid={item.get('target').pid} udid={udid}", method="device_count")
|
||||
@@ -335,13 +376,14 @@ class Deviceinfo(object):
|
||||
if not self._spawn_iproxy:
|
||||
LogManager.error("iproxy 启动器未就绪", udid)
|
||||
return None
|
||||
while self._port_in_use and self._is_port_open(port):
|
||||
for attempt in range(5):
|
||||
if not self._is_port_open(port):
|
||||
break
|
||||
LogManager.warning(f"端口 {port} 仍被占用,第 {attempt+1} 次重试释放", udid)
|
||||
pid = self._get_pid_by_port(port)
|
||||
if pid and pid != os.getpid():
|
||||
LogManager.warning(f"端口 {port} 仍被 PID {pid} 占用,尝试释放", udid)
|
||||
self._kill_pid_gracefully(pid)
|
||||
else:
|
||||
break
|
||||
time.sleep(0.2)
|
||||
try:
|
||||
p = self._spawn_iproxy(udid, port, 9100)
|
||||
self._port_in_use.add(port)
|
||||
@@ -405,4 +447,4 @@ class Deviceinfo(object):
|
||||
for p in candidates:
|
||||
if p.exists():
|
||||
return p
|
||||
raise FileNotFoundError(f"iproxy not found, tried: {[str(c) for c in candidates]}")
|
||||
raise FileNotFoundError(f"iproxy not found, tried: {[str(c) for c in candidates]}")
|
||||
Reference in New Issue
Block a user