继续优化批量停止脚本
This commit is contained in:
@@ -317,59 +317,86 @@ class Deviceinfo(object):
|
||||
|
||||
# 检测usb是否超时
|
||||
def _usb_client_with_timeout(self,udid: str, timeout: 8):
|
||||
LogManager.info(f"[CONNECT FLOW] 即将创建 USBClient(超时 {timeout}s)", udid)
|
||||
with ThreadPoolExecutor(max_workers=1) as exe:
|
||||
fut = exe.submit(wda.USBClient, udid, 8100)
|
||||
return fut.result(timeout=timeout)
|
||||
|
||||
try:
|
||||
client = fut.result(timeout=timeout)
|
||||
LogManager.info("[CONNECT FLOW] USBClient 创建成功", udid)
|
||||
return client
|
||||
except Exception as e:
|
||||
LogManager.error(f"[CONNECT FLOW] USBClient 创建失败(超时或异常): {e}", udid)
|
||||
return None
|
||||
# ------------------------------------------------------------------
|
||||
# 线程池里真正干活的地方(原 connectDevice 逻辑搬过来)
|
||||
# ------------------------------------------------------------------
|
||||
def _connect_device_task(self, udid: str):
|
||||
if not self.is_device_trusted(udid):
|
||||
LogManager.warning("设备未信任,跳过 WDA 启动", udid)
|
||||
return
|
||||
LogManager.info(f"[CONNECT FLOW] >>>>>>>>> 开始处理设备 {udid} >>>>>>>>>", udid)
|
||||
|
||||
d = self._usb_client_with_timeout(udid, 8) # 8 秒必返
|
||||
if d is None:
|
||||
LogManager.info(f"设备链接超时,{udid}")
|
||||
# 1. 信任检测
|
||||
trusted = self.is_device_trusted(udid)
|
||||
LogManager.info(f"[CONNECT FLOW] 信任检测结果 trusted={trusted}", udid)
|
||||
if not trusted:
|
||||
LogManager.warning("[CONNECT FLOW] 设备未信任,直接返回", udid)
|
||||
return
|
||||
LogManager.info("[CONNECT FLOW] 信任检测通过,准备创建 USBClient", udid)
|
||||
|
||||
# 2. 创建 WDA 客户端(带超时)
|
||||
try:
|
||||
d = wda.USBClient(udid, 8100)
|
||||
d = self._usb_client_with_timeout(udid, 8)
|
||||
if d is None:
|
||||
LogManager.error("[CONNECT FLOW] USBClient 返回 None(超时或异常),直接返回", udid)
|
||||
return
|
||||
LogManager.info("[CONNECT FLOW] USBClient 创建成功", udid)
|
||||
except Exception as e:
|
||||
LogManager.error(f"启动 WDA 失败: {e}", udid)
|
||||
LogManager.error(f"[CONNECT FLOW] USBClient 抛异常: {e}", udid)
|
||||
return
|
||||
|
||||
# 3. 读取屏幕信息
|
||||
width, height, scale = 0, 0, 1.0
|
||||
try:
|
||||
size = d.window_size()
|
||||
width, height = size.width, size.height
|
||||
scale = d.scale
|
||||
LogManager.info(f"[CONNECT FLOW] 屏幕信息 width={width} height={height} scale={scale}", udid)
|
||||
except Exception as e:
|
||||
LogManager.warning(f"读取屏幕信息失败:{e}", udid)
|
||||
LogManager.warning(f"[CONNECT FLOW] 读取屏幕信息失败: {e},继续使用默认值", udid)
|
||||
|
||||
# 4. 分配端口
|
||||
port = self._alloc_port()
|
||||
model = DeviceModel(udid, port, width, height, scale, type=1)
|
||||
LogManager.info(f"[CONNECT FLOW] 分配投屏端口 {port}", udid)
|
||||
|
||||
# 先做完所有 IO,再抢锁写内存
|
||||
# 5. 启动 WDA
|
||||
try:
|
||||
LogManager.info("[CONNECT FLOW] 正在启动 WDA 应用", udid)
|
||||
d.app_start(WdaAppBundleId)
|
||||
d.home()
|
||||
LogManager.info("[CONNECT FLOW] WDA 应用启动完成,等待 2s", udid)
|
||||
except Exception as e:
|
||||
LogManager.warning(f"启动/切回桌面失败:{e}", udid)
|
||||
|
||||
time.sleep(2) # 原逻辑保留
|
||||
LogManager.warning(f"[CONNECT FLOW] 启动 WDA 失败: {e},仍继续", udid)
|
||||
time.sleep(2)
|
||||
|
||||
# 6. 启动 iproxy
|
||||
LogManager.info(f"[CONNECT FLOW] 准备启动 iproxy 本地 {port} -> 设备 9100", udid)
|
||||
target = self.relayDeviceScreenPort(udid, port)
|
||||
if target is None:
|
||||
LogManager.error("[CONNECT FLOW] iproxy 启动失败,释放端口并返回", udid)
|
||||
self._free_port(port)
|
||||
return
|
||||
LogManager.info("[CONNECT FLOW] iproxy 启动成功,进程已注册", udid)
|
||||
|
||||
# 毫秒级临界区
|
||||
# 7. 抢锁写内存
|
||||
with self._lock:
|
||||
if udid in self._model_index: # 并发防重
|
||||
if udid in self._model_index:
|
||||
LogManager.warning(f"[CONNECT FLOW] 并发重复,已存在内存中,放弃本次任务", udid)
|
||||
self._terminate_proc(target) # 避免孤儿
|
||||
self._free_port(port)
|
||||
return
|
||||
model = DeviceModel(udid, port, width, height, scale, type=1)
|
||||
self._add_model(model)
|
||||
if target:
|
||||
self.pidList.append({"target": target, "id": udid})
|
||||
self.pidList.append({"target": target, "id": udid})
|
||||
LogManager.info(f"[CONNECT FLOW] 设备模型已加入内存,当前在线数: {len(self.deviceModelList)}", udid)
|
||||
|
||||
LogManager.info(f"[CONNECT FLOW] <<<<<<<<< 设备 {udid} 处理完成 <<<<<<<<", udid)
|
||||
# ------------------------------------------------------------------
|
||||
# 原函数保留(改名即可)
|
||||
# ------------------------------------------------------------------
|
||||
@@ -380,31 +407,41 @@ class Deviceinfo(object):
|
||||
# -------------------- 工具方法(未改动) --------------------
|
||||
def is_device_trusted(self, udid: str) -> bool:
|
||||
try:
|
||||
LogManager.info(f"[CONNECT FLOW] 开始信任检测", udid)
|
||||
d = BaseDevice(udid)
|
||||
d.get_value("DeviceName")
|
||||
name = d.get_value("DeviceName")
|
||||
LogManager.info(f"[CONNECT FLOW] 信任检测成功,DeviceName={name}", udid)
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
LogManager.warning(f"[CONNECT FLOW] 信任检测失败: {e}", udid)
|
||||
return False
|
||||
|
||||
def relayDeviceScreenPort(self, udid: str, port: int) -> Optional[subprocess.Popen]:
|
||||
LogManager.info(f"[CONNECT FLOW] 进入 relayDeviceScreenPort,目标端口 {port}", udid)
|
||||
if not self._spawn_iproxy:
|
||||
LogManager.error("iproxy 启动器未就绪", udid)
|
||||
LogManager.error("[CONNECT FLOW] _spawn_iproxy 未初始化,返回 None", udid)
|
||||
return None
|
||||
|
||||
for attempt in range(5):
|
||||
if not self._is_port_open(port):
|
||||
LogManager.info(f"[CONNECT FLOW] 端口 {port} 检测为空闲", udid)
|
||||
break
|
||||
LogManager.warning(f"端口 {port} 仍被占用,第 {attempt+1} 次重试释放", udid)
|
||||
LogManager.warning(f"[CONNECT FLOW] 端口 {port} 仍被占用,第 {attempt + 1}/5 次尝试释放", udid)
|
||||
pid = self._get_pid_by_port(port)
|
||||
if pid and pid != os.getpid():
|
||||
LogManager.info(f"[CONNECT FLOW] 准备 kill 占用端口 {port} 的 PID {pid}", udid)
|
||||
self._kill_pid_gracefully(pid)
|
||||
time.sleep(0.2)
|
||||
else:
|
||||
LogManager.error("[CONNECT FLOW] 连续 5 次无法释放端口,放弃", udid)
|
||||
return None
|
||||
|
||||
try:
|
||||
p = self._spawn_iproxy(udid, port, 9100)
|
||||
self._port_in_use.add(port)
|
||||
LogManager.info(f"启动 iproxy 成功,本地 {port} -> 设备 9100", udid)
|
||||
LogManager.info(f"[CONNECT FLOW] iproxy 启动完成,PID={p.pid}", udid)
|
||||
return p
|
||||
except Exception as e:
|
||||
LogManager.error(f"启动 iproxy 失败:{e}", udid)
|
||||
LogManager.error(f"[CONNECT FLOW] iproxy 启动异常: {e}", udid)
|
||||
return None
|
||||
|
||||
def _is_port_open(self, port: int) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user