截图使用session,wda挂了之后重建nkAgent卡死
parent
f5dda0f46c
commit
e5d1e6e68b
|
@ -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,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 = 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 {
|
||||||
|
@ -61,25 +70,23 @@ public abstract class IosDeviceInitThread extends Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reTryTime++;
|
reTryTime++;
|
||||||
} while (!nkAgentReady && reTryTime <= 5);
|
}
|
||||||
if (!nkAgentReady) {
|
if (!nkAgentReady) {
|
||||||
|
nkAgent.setOnDisconnectListener(null);
|
||||||
|
nkAgent = null;
|
||||||
|
if (null != process) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
isFBServerReady = false;
|
||||||
throw new ExecuteException(String.format("无法创建设备【%s】nkAgent", phone.getUdid()));
|
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{
|
}else{
|
||||||
logger.warn("设备【{}】的nkAgent失效了,但是已经创建好了,不再创建了...........", phone.getUdid());
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,17 +104,19 @@ 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);
|
||||||
}
|
}
|
||||||
if (!isFBServerReady && line.contains("ServerURLHere")) {
|
|
||||||
isFBServerReady = true;
|
|
||||||
synchronized (waitFbServerReadyLock) {
|
|
||||||
waitFbServerReadyLock.notifyAll();
|
|
||||||
}
|
|
||||||
createNKAgent();
|
|
||||||
apiPortReady();
|
|
||||||
}
|
|
||||||
if (logOutput != null) {
|
|
||||||
logOutput.write(line.getBytes());
|
logOutput.write(line.getBytes());
|
||||||
logOutput.write(10);
|
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) {
|
if (outputLineCallback != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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())) {
|
|
||||||
currentDevice = adbDevice;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (null == currentDevice) {
|
if (null == currentDevice) {
|
||||||
logger.warn("设备【{}】不在线。。。。。",deviceId);
|
throw new ExecuteException("当前设备不在线");
|
||||||
throw new ExecuteException("截图失败,当前设备不在线");
|
|
||||||
}
|
}
|
||||||
logger.warn("设备【{}】没有androidAgent创建一个。。。。。",deviceId);
|
agentSession = new AndroidAgentSession(currentDevice, false);
|
||||||
androidAgent = new AndroidAgent(adb, currentDevice);
|
agentSession.start();
|
||||||
screenShotAgentMap.put(deviceId, androidAgent);
|
screenShotAgentSessionMap.put(deviceId, agentSession);
|
||||||
} else {
|
} 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) {
|
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");
|
||||||
|
|
Loading…
Reference in New Issue