截图阻塞的问题
parent
c05ca15444
commit
696d51ea04
|
@ -0,0 +1,42 @@
|
||||||
|
package net.northking.cctp.upperComputer.driver.agent;
|
||||||
|
|
||||||
|
import net.northking.cctp.upperComputer.driver.adb.Adb;
|
||||||
|
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 与Android Agent程序进行交互
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AndroidAgent{
|
||||||
|
|
||||||
|
private Logger logger = LoggerFactory.getLogger(AndroidAgent.class);
|
||||||
|
|
||||||
|
private final Adb adb;
|
||||||
|
private final AdbDevice adbDevice;
|
||||||
|
|
||||||
|
public AndroidAgent(Adb adb, AdbDevice adbDevice) {
|
||||||
|
this.adb = adb;
|
||||||
|
this.adbDevice = adbDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] takeScreenshot() {
|
||||||
|
byte[] result = null;
|
||||||
|
StandaloneCommandRunner runner = new StandaloneCommandRunner(adb, adbDevice, "net.northking.product.cctpplus.command.ScreenShotCommand", "");
|
||||||
|
try {
|
||||||
|
result = runner.run();
|
||||||
|
} catch (StandaloneCommandTimeoutException e) {
|
||||||
|
logger.error("Android Agent执行超时", e);
|
||||||
|
} catch (StandaloneCommandException e) {
|
||||||
|
logger.error("Android Agent执行异常", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Android Agent执行IO异常", e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package net.northking.cctp.upperComputer.driver.agent;
|
||||||
|
|
||||||
|
public class StandaloneCommandException extends Exception {
|
||||||
|
public StandaloneCommandException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package net.northking.cctp.upperComputer.driver.agent;
|
||||||
|
|
||||||
|
import net.northking.cctp.upperComputer.driver.adb.Adb;
|
||||||
|
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
|
||||||
|
import net.northking.cctp.upperComputer.driver.adb.AdbTransport;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class StandaloneCommandRunner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态正常,输出指令应该输出的数据
|
||||||
|
*/
|
||||||
|
private static final int STATUS_CODE_OK = 0;
|
||||||
|
/**
|
||||||
|
* 执行超时,不附带任何数据
|
||||||
|
*/
|
||||||
|
private static final int STATUS_CODE_TIMEOUT = -1;
|
||||||
|
/**
|
||||||
|
* 执行时发生异常,输出异常堆栈文本
|
||||||
|
*/
|
||||||
|
private static final int STATUS_CODE_EXCEPTION = -2;
|
||||||
|
|
||||||
|
private final Adb adb;
|
||||||
|
private final AdbDevice adbDevice;
|
||||||
|
private final String className;
|
||||||
|
private String args = "";
|
||||||
|
|
||||||
|
|
||||||
|
public StandaloneCommandRunner(Adb adb, AdbDevice adbDevice, String className, String args) {
|
||||||
|
this.className = className;
|
||||||
|
this.adb = adb;
|
||||||
|
this.adbDevice = adbDevice;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] run() throws StandaloneCommandException, StandaloneCommandTimeoutException, IOException {
|
||||||
|
try (AdbTransport transport = adb.shell(adbDevice, "export CLASSPATH=/data/local/tmp/agent.apk;app_process /system/bin " + className + " " + args)) {
|
||||||
|
DataInputStream dataInput = getDataInputStream(transport);
|
||||||
|
int status = dataInput.readInt();
|
||||||
|
switch (status) {
|
||||||
|
case STATUS_CODE_OK:
|
||||||
|
int dataLength = dataInput.readInt();
|
||||||
|
byte[] data = new byte[dataLength];
|
||||||
|
dataInput.readFully(data);
|
||||||
|
return data;
|
||||||
|
case STATUS_CODE_TIMEOUT:
|
||||||
|
throw new StandaloneCommandTimeoutException("Agent独立指令:class:" + className + " args:" + args + " 超时");
|
||||||
|
case STATUS_CODE_EXCEPTION:
|
||||||
|
dataLength = dataInput.readInt();
|
||||||
|
data = new byte[dataLength];
|
||||||
|
dataInput.readFully(data);
|
||||||
|
throw new StandaloneCommandException(new String(data));
|
||||||
|
default:
|
||||||
|
throw new IOException("Agent独立指令:class:" + className + " args:" + args + " 未知状态码:" + status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataInputStream getDataInputStream(AdbTransport transport) throws IOException {
|
||||||
|
if (transport == null) {
|
||||||
|
throw new IOException("无法创建Shell");
|
||||||
|
}
|
||||||
|
InputStream inputStream = transport.getInputStream();
|
||||||
|
int bannerCount = 0;
|
||||||
|
while (bannerCount < 5) {
|
||||||
|
int b = inputStream.read();
|
||||||
|
if (b == -1) {
|
||||||
|
throw new EOFException("Agent独立指令:class:" + className + " args:" + args + " 未能读取到banner");
|
||||||
|
}
|
||||||
|
if (b == (byte) 0x01) {
|
||||||
|
bannerCount++;
|
||||||
|
} else {
|
||||||
|
bannerCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new DataInputStream(inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package net.northking.cctp.upperComputer.driver.agent;
|
||||||
|
|
||||||
|
public class StandaloneCommandTimeoutException extends Exception {
|
||||||
|
public StandaloneCommandTimeoutException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import net.northking.cctp.upperComputer.deviceManager.thread.AndroidDeviceInitTh
|
||||||
import net.northking.cctp.upperComputer.driver.adb.Adb;
|
import net.northking.cctp.upperComputer.driver.adb.Adb;
|
||||||
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
|
import net.northking.cctp.upperComputer.driver.adb.AdbDevice;
|
||||||
import net.northking.cctp.upperComputer.driver.adb.AdbTransport;
|
import net.northking.cctp.upperComputer.driver.adb.AdbTransport;
|
||||||
|
import net.northking.cctp.upperComputer.driver.agent.AndroidAgent;
|
||||||
import net.northking.cctp.upperComputer.driver.agent.AndroidAgentSession;
|
import net.northking.cctp.upperComputer.driver.agent.AndroidAgentSession;
|
||||||
import net.northking.cctp.upperComputer.driver.agent.command.*;
|
import net.northking.cctp.upperComputer.driver.agent.command.*;
|
||||||
import net.northking.cctp.upperComputer.enums.FileBusinessTypeEnum;
|
import net.northking.cctp.upperComputer.enums.FileBusinessTypeEnum;
|
||||||
|
@ -36,6 +37,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -64,7 +66,7 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
|
||||||
|
|
||||||
private ConcurrentHashMap<String, AndroidDeviceAllInfoThread> queryDeviceInfoMap = new ConcurrentHashMap<>();
|
private ConcurrentHashMap<String, AndroidDeviceAllInfoThread> queryDeviceInfoMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private ConcurrentHashMap<String, AndroidAgentSession> screenShotAgentSessionMap = new ConcurrentHashMap<>();
|
private ConcurrentHashMap<String, AndroidAgent> screenShotAgentMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private Adb adb;
|
private Adb adb;
|
||||||
|
|
||||||
|
@ -961,38 +963,35 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
|
||||||
|
|
||||||
private File getScreenShotInCommand(String deviceId) {
|
private File getScreenShotInCommand(String deviceId) {
|
||||||
File tmpPicFile = null;
|
File tmpPicFile = null;
|
||||||
AndroidAgentSession agentSession = null;
|
|
||||||
try {
|
try {
|
||||||
agentSession = screenShotAgentSessionMap.get(deviceId);
|
AndroidAgent androidAgent = screenShotAgentMap.get(deviceId);
|
||||||
if (null == agentSession || !agentSession.isState()) {
|
if (null == androidAgent) {
|
||||||
AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId);
|
AdbDevice currentDevice = null;
|
||||||
|
ArrayList<AdbDevice> adbDevices = adb.listDevices();
|
||||||
|
if (!CollectionUtils.isEmpty(adbDevices)) {
|
||||||
|
for (AdbDevice adbDevice : adbDevices) {
|
||||||
|
if (deviceId.equals(adbDevice.getSerial())) {
|
||||||
|
currentDevice = adbDevice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (null == currentDevice) {
|
if (null == currentDevice) {
|
||||||
throw new ExecuteException("当前设备不在线");
|
logger.warn("设备【{}】不在线。。。。。",deviceId);
|
||||||
|
throw new ExecuteException("截图失败,当前设备不在线");
|
||||||
}
|
}
|
||||||
agentSession = new AndroidAgentSession(currentDevice, false);
|
logger.warn("设备【{}】没有androidAgent创建一个。。。。。",deviceId);
|
||||||
agentSession.start();
|
androidAgent = new AndroidAgent(adb, currentDevice);
|
||||||
screenShotAgentSessionMap.put(deviceId, agentSession);
|
screenShotAgentMap.put(deviceId, androidAgent);
|
||||||
} else {
|
} else {
|
||||||
String send = agentSession.send(new EchoCommand("hello")); //检查
|
logger.warn("设备【{}】已经存在androidAgent。。。。。",deviceId);
|
||||||
if (!"hello".equals(send)) {
|
|
||||||
logger.warn("设备【{}】当前使用的截图的session失效了,重新创建一个。。。。。",deviceId);
|
|
||||||
AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId);
|
|
||||||
if (null == currentDevice) {
|
|
||||||
throw new ExecuteException("当前设备不在线");
|
|
||||||
}
|
}
|
||||||
agentSession = new AndroidAgentSession(currentDevice, false);
|
byte[] screenShotData = androidAgent.takeScreenshot();
|
||||||
agentSession.start();
|
if (null != screenShotData && screenShotData.length > 0) {
|
||||||
screenShotAgentSessionMap.put(deviceId, agentSession);
|
logger.debug("收到手机【{}】截图,大小:{}",deviceId,screenShotData.length);
|
||||||
} else {
|
|
||||||
logger.debug("设备【{}】当前使用的截图的session还能用,继续使用。。。。。",deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte[] screenShotData = agentSession.send(TakeScreenshotCommand.getInstance());
|
|
||||||
if (null != screenShotData && screenShotData.length > 0) { //截图
|
|
||||||
logger.debug("收到手机【{}】截图,大小:{}", deviceId, screenShotData.length);
|
|
||||||
File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic");
|
File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic");
|
||||||
if (!tmpPicDir.exists()) {
|
if (!tmpPicDir.exists()) {
|
||||||
tmpPicDir.mkdir();
|
tmpPicDir.mkdirs();
|
||||||
}
|
}
|
||||||
String tmpPicPath = tmpPicDir.getAbsolutePath() + "/" + deviceId + "_" + System.currentTimeMillis() + ".png";
|
String tmpPicPath = tmpPicDir.getAbsolutePath() + "/" + deviceId + "_" + System.currentTimeMillis() + ".png";
|
||||||
tmpPicFile = new File(tmpPicPath);
|
tmpPicFile = new File(tmpPicPath);
|
||||||
|
@ -1004,8 +1003,6 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService {
|
||||||
}
|
}
|
||||||
}catch (Exception e) {
|
}catch (Exception e) {
|
||||||
logger.error("设备【"+deviceId+"】截图异常",e);
|
logger.error("设备【"+deviceId+"】截图异常",e);
|
||||||
}finally {
|
|
||||||
logger.debug("设备【{}】写到本地的图片大小:{}", deviceId, tmpPicFile != null ? tmpPicFile.length() : 0);
|
|
||||||
}
|
}
|
||||||
return tmpPicFile;
|
return tmpPicFile;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue