截图使用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;
/**
* wda
*/
protected Process process;
protected boolean isFBServerReady = false;
private int frame = 12;
public IosDeviceInitThread(PhoneEntity phone, AppleDevice appleDevice) {
@ -36,22 +44,23 @@ 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.setOnDisconnectListener(() -> {
if(!isFBServerReady) return;
logger.warn("设备【{}】的nkAgent失效了需要重新创建...........", phone.getUdid());
createNKAgent("回调重试");
logger.warn("设备【{}】的nkAgent重新创建完成...........", phone.getUdid());
});
boolean nkAgentReady = false;
int reTryTime = 1;
do {
while (!nkAgentReady && reTryTime <= 5 && isFBServerReady) {
logger.debug("尝试第{}次连接设备【{}】的nkAgent", reTryTime, phone.getUdid());
try {
nkAgent.connect();
nkAgentReady = nkAgent.getStatus();
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) {
logger.error("第{}次连接设备【{}】的agent出错", reTryTime, phone.getUdid(), e);
try {
@ -61,25 +70,23 @@ public abstract class IosDeviceInitThread extends Thread {
}
}
reTryTime++;
} while (!nkAgentReady && reTryTime <= 5);
}
if (!nkAgentReady) {
nkAgent.setOnDisconnectListener(null);
nkAgent = null;
if (null != process) {
process.destroy();
}
isFBServerReady = false;
throw new ExecuteException(String.format("无法创建设备【%s】nkAgent", phone.getUdid()));
}
logger.debug("设置设备【{}】的nkAgent掉线之后的监听器................", phone.getUdid());
nkAgent.setOnDisconnectListener(() -> {
synchronized (nkAgent) {
if (!nkAgent.getStatus()) {
logger.warn("设备【{}】的nkAgent失效了需要重新创建...........", phone.getUdid());
IOSDeviceManager.getInstance().getIosInitThread(phone.getUdid()).createNKAgent();
logger.warn("设备【{}】的nkAgent重新创建完成...........", phone.getUdid());
}else{
logger.warn("设备【{}】的nkAgent失效了但是已经创建好了不再创建了...........", phone.getUdid());
logger.debug("设置设备【{}】的帧数为:{}", phone.getUdid(), frame);
nkAgent.setMJPEGServerRate(frame);
}
}
});
logger.debug("设备【{}】的nkAgent连接完毕................", phone.getUdid());
}
public NKAgent getNkAgent() {
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.usbmuxd.AppleDevice;
import net.northking.cctp.upperComputer.entity.PhoneEntity;
import net.northking.cctp.upperComputer.exception.ExecuteException;
import net.northking.cctp.upperComputer.utils.SpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,11 +32,6 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
*/
public static final int IOS_CORE_DEVICE_VERSION = 17;
/**
* xcodebuild
*/
private Process process = null;
/**
* xcodebuild退
*/
@ -47,10 +43,6 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
private OutputLineCallback outputLineCallback;
private boolean isFBServerReady = false;
private final Object waitFbServerReadyLock = new Object();
public MacIosDeviceInitThread(PhoneEntity phoneEntity, AppleDevice device) {
super(phoneEntity, device);
init();
@ -112,17 +104,19 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
if (wdaConfig.isPrintWdaOutput()) {
logger.debug("WDA-" + appleDevice.getConnectionDetail().serialNumber + "->" + line);
}
if (!isFBServerReady && line.contains("ServerURLHere")) {
isFBServerReady = true;
synchronized (waitFbServerReadyLock) {
waitFbServerReadyLock.notifyAll();
}
createNKAgent();
apiPortReady();
}
if (logOutput != null) {
logOutput.write(line.getBytes());
logOutput.write(10);
if (!isFBServerReady && line.contains("ServerURLHere")) {
logger.debug("发现WDA启动完成信号");
isFBServerReady = true;
try {
createNKAgent("WDA启动");
} catch (ExecuteException e) {
logger.error("WDA启动后创建NKAgent失败", e);
process.destroy();
break;
}
apiPortReady();
}
if (outputLineCallback != null) {
try {
@ -150,20 +144,22 @@ public class MacIosDeviceInitThread extends IosDeviceInitThread {
}
}
}
isFBServerReady = false;
if (nkAgent != null) {
nkAgent.setOnDisconnectListener(null);
}
try {
exitCode = process.waitFor();
} catch (InterruptedException ignored) {
break;
}
if (logOutput != null) {
try {
logOutput.close();
} catch (IOException e) {
logger.warn("关闭WDA独立日志流时发生IO异常路径:{}", logFileName, e);
}
}
IOSDeviceManager.getInstance().publishDeviceAgentDead(phone.getUdid());
logger.debug("设备【{}】的wda退出了,重启一次......................", appleDevice.getConnectionDetail().serialNumber);
isFBServerReady = false;
}
logger.debug("设备【{}】的wda退出了,不在重启了......................", appleDevice.getConnectionDetail().serialNumber);
}

View File

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

View File

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

View File

@ -50,7 +50,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
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.UNICODE_KEYBOARD;
@ -74,6 +74,10 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
private ConcurrentHashMap<String, AndroidAgent> screenShotAgentMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, AndroidAgentSession> screenShotAgentSessionMap = new ConcurrentHashMap<>();
private ExecutorService service = Executors.newFixedThreadPool(10);
private Adb adb;
@Autowired
@ -1018,30 +1022,57 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
private File getScreenShotInCommand(String deviceId) {
File tmpPicFile = null;
try {
AndroidAgent androidAgent = screenShotAgentMap.get(deviceId);
if (null == androidAgent) {
AdbDevice currentDevice = null;
ArrayList<AdbDevice> adbDevices = adb.listDevices();
if (!CollectionUtils.isEmpty(adbDevices)) {
for (AdbDevice adbDevice : adbDevices) {
if (deviceId.equals(adbDevice.getSerial())) {
currentDevice = adbDevice;
break;
}
}
}
byte[] screenShotData = null;
Future<byte[]> submit = service.submit(new Callable<byte[]>() {
@Override
public byte[] call() throws Exception {
AndroidAgentSession agentSession = screenShotAgentSessionMap.get(deviceId);
if (null == agentSession || !agentSession.isState()) {
AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId);
if (null == currentDevice) {
logger.warn("设备【{}】不在线。。。。。",deviceId);
throw new ExecuteException("截图失败,当前设备不在线");
throw new ExecuteException("当前设备不在线");
}
logger.warn("设备【{}】没有androidAgent创建一个。。。。。",deviceId);
androidAgent = new AndroidAgent(adb, currentDevice);
screenShotAgentMap.put(deviceId, androidAgent);
agentSession = new AndroidAgentSession(currentDevice, false);
agentSession.start();
screenShotAgentSessionMap.put(deviceId, agentSession);
} else {
logger.warn("设备【{}】已经存在androidAgent。。。。。",deviceId);
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;
}
byte[] screenShotData = androidAgent.takeScreenshot();
agentSession = new AndroidAgentSession(currentDevice, false);
agentSession.start();
screenShotAgentSessionMap.put(deviceId, agentSession);
} else {
logger.debug("设备【{}】当前使用的截图的session还能用继续使用。。。。。", deviceId);
}
}
byte[] temData = agentSession.send(TakeScreenshotCommand.getInstance());
return temData;
}
});
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) {
logger.debug("收到手机【{}】截图,大小:{}",deviceId,screenShotData.length);
File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic");