截图使用session,wda挂了之后重建nkAgent卡死

master
yineng.huang 2024-11-04 19:35:21 +08:00
parent f5dda0f46c
commit e5d1e6e68b
5 changed files with 112 additions and 79 deletions

View File

@ -27,6 +27,14 @@ public abstract class IosDeviceInitThread extends Thread {
protected AppleDevice appleDevice; protected AppleDevice appleDevice;
/**
* wda
*/
protected Process process;
protected boolean isFBServerReady = false;
private int frame = 12; private int frame = 12;
public IosDeviceInitThread(PhoneEntity phone, AppleDevice appleDevice) { public IosDeviceInitThread(PhoneEntity phone, AppleDevice appleDevice) {
@ -36,24 +44,25 @@ public abstract class IosDeviceInitThread extends Thread {
} }
protected void createNKAgent() { protected synchronized void createNKAgent(String tag) {
logger.debug("createNKAgent:{}",tag);
nkAgent = new NKAgent(this.appleDevice); nkAgent = new NKAgent(this.appleDevice);
nkAgent.setOnDisconnectListener(() -> {
if(!isFBServerReady) return;
logger.warn("设备【{}】的nkAgent失效了需要重新创建...........", phone.getUdid());
createNKAgent("回调重试");
logger.warn("设备【{}】的nkAgent重新创建完成...........", phone.getUdid());
});
boolean nkAgentReady = false; boolean nkAgentReady = false;
int reTryTime = 1; int reTryTime = 1;
do { while (!nkAgentReady && reTryTime <= 5 && isFBServerReady) {
logger.debug("尝试第{}次连接设备【{}】的nkAgent", reTryTime, phone.getUdid()); logger.debug("尝试第{}次连接设备【{}】的nkAgent", reTryTime, phone.getUdid());
try { try {
nkAgent.connect(); nkAgent.connect();
nkAgentReady = nkAgent.getStatus(); nkAgentReady = nkAgent.getStatus();
logger.debug("设备【{}】的nkAgent连接完成结果{}", phone.getUdid(),nkAgentReady); logger.debug("设备【{}】的nkAgent连接完成结果{}", phone.getUdid(), nkAgentReady);
if (nkAgentReady) {
logger.debug("设置设备【{}】的帧数为:{}", phone.getUdid(), frame);
nkAgent.setMJPEGServerRate(frame);
} else {
logger.error("第{}次连接设备【{}】的agent不成功等待下一次......",reTryTime, phone.getUdid());
}
} catch (IOException e) { } catch (IOException e) {
logger.error("第{}次连接设备【{}】的agent出错",reTryTime, phone.getUdid(), e); logger.error("第{}次连接设备【{}】的agent出错", reTryTime, phone.getUdid(), e);
try { try {
Thread.sleep(3000); Thread.sleep(3000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
@ -61,25 +70,23 @@ public abstract class IosDeviceInitThread extends Thread {
} }
} }
reTryTime++; reTryTime++;
} while (!nkAgentReady && reTryTime <= 5);
if (!nkAgentReady) {
throw new ExecuteException(String.format("无法创建设备【%s】nkAgent", phone.getUdid()));
} }
logger.debug("设置设备【{}】的nkAgent掉线之后的监听器................", phone.getUdid()); if (!nkAgentReady) {
nkAgent.setOnDisconnectListener(() -> { nkAgent.setOnDisconnectListener(null);
synchronized (nkAgent) { nkAgent = null;
if (!nkAgent.getStatus()) { if (null != process) {
logger.warn("设备【{}】的nkAgent失效了需要重新创建...........", phone.getUdid()); process.destroy();
IOSDeviceManager.getInstance().getIosInitThread(phone.getUdid()).createNKAgent();
logger.warn("设备【{}】的nkAgent重新创建完成...........", phone.getUdid());
} else {
logger.warn("设备【{}】的nkAgent失效了但是已经创建好了不再创建了...........", phone.getUdid());
}
} }
}); isFBServerReady = false;
throw new ExecuteException(String.format("无法创建设备【%s】nkAgent", phone.getUdid()));
}else{
logger.debug("设置设备【{}】的帧数为:{}", phone.getUdid(), frame);
nkAgent.setMJPEGServerRate(frame);
}
logger.debug("设备【{}】的nkAgent连接完毕................", phone.getUdid()); logger.debug("设备【{}】的nkAgent连接完毕................", phone.getUdid());
} }
public NKAgent getNkAgent() { public NKAgent getNkAgent() {
return nkAgent; return nkAgent;
} }

View File

@ -12,6 +12,7 @@ import net.northking.cctp.upperComputer.driver.ios.NKAgent;
import net.northking.cctp.upperComputer.driver.ios.command.data.ScreenInfoData; import net.northking.cctp.upperComputer.driver.ios.command.data.ScreenInfoData;
import net.northking.cctp.upperComputer.driver.usbmuxd.AppleDevice; import net.northking.cctp.upperComputer.driver.usbmuxd.AppleDevice;
import net.northking.cctp.upperComputer.entity.PhoneEntity; import net.northking.cctp.upperComputer.entity.PhoneEntity;
import net.northking.cctp.upperComputer.exception.ExecuteException;
import net.northking.cctp.upperComputer.utils.SpringUtils; import net.northking.cctp.upperComputer.utils.SpringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,11 +32,6 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
*/ */
public static final int IOS_CORE_DEVICE_VERSION = 17; public static final int IOS_CORE_DEVICE_VERSION = 17;
/**
* xcodebuild
*/
private Process process = null;
/** /**
* xcodebuild退 * xcodebuild退
*/ */
@ -47,10 +43,6 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
private OutputLineCallback outputLineCallback; private OutputLineCallback outputLineCallback;
private boolean isFBServerReady = false;
private final Object waitFbServerReadyLock = new Object();
public MacIosDeviceInitThread(PhoneEntity phoneEntity, AppleDevice device) { public MacIosDeviceInitThread(PhoneEntity phoneEntity, AppleDevice device) {
super(phoneEntity, device); super(phoneEntity, device);
init(); init();
@ -112,18 +104,20 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
if (wdaConfig.isPrintWdaOutput()) { if (wdaConfig.isPrintWdaOutput()) {
logger.debug("WDA-" + appleDevice.getConnectionDetail().serialNumber + "->" + line); logger.debug("WDA-" + appleDevice.getConnectionDetail().serialNumber + "->" + line);
} }
logOutput.write(line.getBytes());
logOutput.write(10);
if (!isFBServerReady && line.contains("ServerURLHere")) { if (!isFBServerReady && line.contains("ServerURLHere")) {
logger.debug("发现WDA启动完成信号");
isFBServerReady = true; isFBServerReady = true;
synchronized (waitFbServerReadyLock) { try {
waitFbServerReadyLock.notifyAll(); createNKAgent("WDA启动");
} catch (ExecuteException e) {
logger.error("WDA启动后创建NKAgent失败", e);
process.destroy();
break;
} }
createNKAgent();
apiPortReady(); apiPortReady();
} }
if (logOutput != null) {
logOutput.write(line.getBytes());
logOutput.write(10);
}
if (outputLineCallback != null) { if (outputLineCallback != null) {
try { try {
outputLineCallback.onLine(line); outputLineCallback.onLine(line);
@ -134,7 +128,7 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
} }
} catch (IOException e) { } catch (IOException e) {
logger.warn("读取WDA输出时发生IO异常设备" + appleDevice.getConnectionDetail().serialNumber, e); logger.warn("读取WDA输出时发生IO异常设备" + appleDevice.getConnectionDetail().serialNumber, e);
}finally { } finally {
if (null != inputStreamReader) { if (null != inputStreamReader) {
try { try {
inputStreamReader.close(); inputStreamReader.close();
@ -150,20 +144,22 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
} }
} }
} }
isFBServerReady = false;
if (nkAgent != null) {
nkAgent.setOnDisconnectListener(null);
}
try { try {
exitCode = process.waitFor(); exitCode = process.waitFor();
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
break; break;
} }
if (logOutput != null) { try {
try { logOutput.close();
logOutput.close(); } catch (IOException e) {
} catch (IOException e) { logger.warn("关闭WDA独立日志流时发生IO异常路径:{}", logFileName, e);
logger.warn("关闭WDA独立日志流时发生IO异常路径:{}", logFileName, e);
}
} }
IOSDeviceManager.getInstance().publishDeviceAgentDead(phone.getUdid());
logger.debug("设备【{}】的wda退出了,重启一次......................", appleDevice.getConnectionDetail().serialNumber); logger.debug("设备【{}】的wda退出了,重启一次......................", appleDevice.getConnectionDetail().serialNumber);
isFBServerReady = false;
} }
logger.debug("设备【{}】的wda退出了,不在重启了......................", appleDevice.getConnectionDetail().serialNumber); logger.debug("设备【{}】的wda退出了,不在重启了......................", appleDevice.getConnectionDetail().serialNumber);
} }

View File

@ -35,8 +35,6 @@ public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
super(phone,device); super(phone,device);
} }
private Process wdaProcess;
@Override @Override
public void run() { public void run() {
logger.debug("不是mac作为上位机用tidevice启动wda"); logger.debug("不是mac作为上位机用tidevice启动wda");
@ -91,13 +89,12 @@ public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
FileOutputStream fileOutputStream = null; FileOutputStream fileOutputStream = null;
try { try {
fileOutputStream = new FileOutputStream(wdaLogFile); fileOutputStream = new FileOutputStream(wdaLogFile);
this.wdaProcess = processBuilder.start(); this.process = processBuilder.start();
if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Windows")) { if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Windows")) {
input = new LineNumberReader(new InputStreamReader(this.wdaProcess.getInputStream(),"GBK")); input = new LineNumberReader(new InputStreamReader(this.process.getInputStream(),"GBK"));
} else if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Linux")) { } else if (UpperComputerManager.getInstance().getOperatingSystem().startsWith("Linux")) {
input = new LineNumberReader(new InputStreamReader(this.wdaProcess.getInputStream(),"UTF-8")); input = new LineNumberReader(new InputStreamReader(this.process.getInputStream(),"UTF-8"));
} }
input = new LineNumberReader(new InputStreamReader(this.wdaProcess.getInputStream()));
String line = null; String line = null;
while (null != (line = input.readLine())) { while (null != (line = input.readLine())) {
if (line.contains("NKLog:")) { if (line.contains("NKLog:")) {
@ -106,7 +103,8 @@ public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
} }
if (line.contains(SUCCESS_FLAG)) { if (line.contains(SUCCESS_FLAG)) {
logger.info("设备【{}】的wda程序启动成功开启nkAgent。。。。。。。。。", phone.getUdid()); logger.info("设备【{}】的wda程序启动成功开启nkAgent。。。。。。。。。", phone.getUdid());
createNKAgent(); isFBServerReady = true;
createNKAgent("非macOS启动wda第一创建NKAgent");
logger.info("设备【{}】即将启动8100端口代理。。。。。。。。。", phone.getUdid()); logger.info("设备【{}】即将启动8100端口代理。。。。。。。。。", phone.getUdid());
apiProxyThread = new Device8100WatchThread(phone); apiProxyThread = new Device8100WatchThread(phone);
apiProxyThread.start(); apiProxyThread.start();
@ -125,7 +123,7 @@ public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
} }
int code = 0; int code = 0;
try { try {
code = this.wdaProcess.waitFor(); code = this.process.waitFor();
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.warn("wda线程中断了。。。。"); logger.warn("wda线程中断了。。。。");
interrupt(); interrupt();
@ -254,7 +252,7 @@ public class WindowsAndLinuxIosDeviceInitThread extends IosDeviceInitThread {
} }
public void exitWdaAndProxy() { public void exitWdaAndProxy() {
this.wdaProcess.destroyForcibly(); this.process.destroy();
interrupt(); interrupt();
} }

View File

@ -201,7 +201,8 @@ public class PacketTransfer {
return connected; return connected;
} }
private void onDisconnected() { private synchronized void onDisconnected() {
if (!connected) return;
connected = false; connected = false;
sendHandler.stop(); sendHandler.stop();
receiveHandler.stop(); receiveHandler.stop();

View File

@ -50,7 +50,7 @@ import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.*;
import static io.appium.java_client.remote.AndroidMobileCapabilityType.RESET_KEYBOARD; import static io.appium.java_client.remote.AndroidMobileCapabilityType.RESET_KEYBOARD;
import static io.appium.java_client.remote.AndroidMobileCapabilityType.UNICODE_KEYBOARD; import static io.appium.java_client.remote.AndroidMobileCapabilityType.UNICODE_KEYBOARD;
@ -74,6 +74,10 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
private ConcurrentHashMap<String, AndroidAgent> screenShotAgentMap = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, AndroidAgent> screenShotAgentMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, AndroidAgentSession> screenShotAgentSessionMap = new ConcurrentHashMap<>();
private ExecutorService service = Executors.newFixedThreadPool(10);
private Adb adb; private Adb adb;
@Autowired @Autowired
@ -1018,30 +1022,57 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
private File getScreenShotInCommand(String deviceId) { private File getScreenShotInCommand(String deviceId) {
File tmpPicFile = null; File tmpPicFile = null;
try { byte[] screenShotData = null;
AndroidAgent androidAgent = screenShotAgentMap.get(deviceId); Future<byte[]> submit = service.submit(new Callable<byte[]>() {
if (null == androidAgent) { @Override
AdbDevice currentDevice = null; public byte[] call() throws Exception {
ArrayList<AdbDevice> adbDevices = adb.listDevices(); AndroidAgentSession agentSession = screenShotAgentSessionMap.get(deviceId);
if (!CollectionUtils.isEmpty(adbDevices)) { if (null == agentSession || !agentSession.isState()) {
for (AdbDevice adbDevice : adbDevices) { AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId);
if (deviceId.equals(adbDevice.getSerial())) { if (null == currentDevice) {
currentDevice = adbDevice; throw new ExecuteException("当前设备不在线");
break; }
agentSession = new AndroidAgentSession(currentDevice, false);
agentSession.start();
screenShotAgentSessionMap.put(deviceId, agentSession);
} else {
String send = agentSession.send(new EchoCommand("hello")); //检查
if (!"hello".equals(send)) {
logger.warn("设备【{}】当前使用的截图的session失效了重新创建一个。。。。。", deviceId);
agentSession.closeSilence();
AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId);
if (null == currentDevice) {
return null;
} }
agentSession = new AndroidAgentSession(currentDevice, false);
agentSession.start();
screenShotAgentSessionMap.put(deviceId, agentSession);
} else {
logger.debug("设备【{}】当前使用的截图的session还能用继续使用。。。。。", deviceId);
} }
} }
if (null == currentDevice) { byte[] temData = agentSession.send(TakeScreenshotCommand.getInstance());
logger.warn("设备【{}】不在线。。。。。",deviceId); return temData;
throw new ExecuteException("截图失败,当前设备不在线");
}
logger.warn("设备【{}】没有androidAgent创建一个。。。。。",deviceId);
androidAgent = new AndroidAgent(adb, currentDevice);
screenShotAgentMap.put(deviceId, androidAgent);
} else {
logger.warn("设备【{}】已经存在androidAgent。。。。。",deviceId);
} }
byte[] screenShotData = androidAgent.takeScreenshot(); });
try {
screenShotData = submit.get(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.debug("设备【{}】截图的时候被中断了。。。。。", deviceId);
return null;
} catch (ExecutionException e) {
logger.error("设备【{}】截图的时候报错了。。。。。", deviceId,e);
return null;
} catch (TimeoutException e) {
logger.debug("设备【{}】截图的时候超时了。。。。。", deviceId,e);
submit.cancel(true);
AndroidAgentSession agentSession = screenShotAgentSessionMap.remove(deviceId);
if (null != agentSession) {
agentSession.closeSilence();
}
return null;
}
try {
if (null != screenShotData && screenShotData.length > 0) { if (null != screenShotData && screenShotData.length > 0) {
logger.debug("收到手机【{}】截图,大小:{}",deviceId,screenShotData.length); logger.debug("收到手机【{}】截图,大小:{}",deviceId,screenShotData.length);
File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic"); File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic");