From 696d51ea042530614114aeea9ff83e6b7c921745 Mon Sep 17 00:00:00 2001 From: "yineng.huang" Date: Wed, 31 Jul 2024 14:34:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=88=AA=E5=9B=BE=E9=98=BB=E5=A1=9E=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../driver/agent/AndroidAgent.java | 42 ++++++++++ .../agent/StandaloneCommandException.java | 7 ++ .../driver/agent/StandaloneCommandRunner.java | 84 +++++++++++++++++++ .../StandaloneCommandTimeoutException.java | 8 ++ .../service/AndroidDebuggerServiceImpl.java | 61 +++++++------- 5 files changed, 170 insertions(+), 32 deletions(-) create mode 100644 cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/AndroidAgent.java create mode 100644 cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandException.java create mode 100644 cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandRunner.java create mode 100644 cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandTimeoutException.java diff --git a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/AndroidAgent.java b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/AndroidAgent.java new file mode 100644 index 0000000..119f306 --- /dev/null +++ b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/AndroidAgent.java @@ -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; + } + + +} diff --git a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandException.java b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandException.java new file mode 100644 index 0000000..90d3c48 --- /dev/null +++ b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandException.java @@ -0,0 +1,7 @@ +package net.northking.cctp.upperComputer.driver.agent; + +public class StandaloneCommandException extends Exception { + public StandaloneCommandException(String message) { + super(message); + } +} diff --git a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandRunner.java b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandRunner.java new file mode 100644 index 0000000..45fb81b --- /dev/null +++ b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandRunner.java @@ -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); + } + + +} diff --git a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandTimeoutException.java b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandTimeoutException.java new file mode 100644 index 0000000..351c176 --- /dev/null +++ b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/driver/agent/StandaloneCommandTimeoutException.java @@ -0,0 +1,8 @@ +package net.northking.cctp.upperComputer.driver.agent; + +public class StandaloneCommandTimeoutException extends Exception { + public StandaloneCommandTimeoutException(String msg) { + super(msg); + } + +} diff --git a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/service/AndroidDebuggerServiceImpl.java b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/service/AndroidDebuggerServiceImpl.java index f7a525f..5b540b1 100644 --- a/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/service/AndroidDebuggerServiceImpl.java +++ b/cctp-atu/atu-upper-computer/src/main/java/net/northking/cctp/upperComputer/service/AndroidDebuggerServiceImpl.java @@ -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.AdbDevice; 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.command.*; 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.http.HttpHeaders; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import java.io.*; @@ -64,7 +66,7 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService { private ConcurrentHashMap queryDeviceInfoMap = new ConcurrentHashMap<>(); - private ConcurrentHashMap screenShotAgentSessionMap = new ConcurrentHashMap<>(); + private ConcurrentHashMap screenShotAgentMap = new ConcurrentHashMap<>(); private Adb adb; @@ -961,51 +963,46 @@ public class AndroidDebuggerServiceImpl extends AbstractDebuggerService { private File getScreenShotInCommand(String deviceId) { File tmpPicFile = null; - AndroidAgentSession agentSession = null; try { - agentSession = screenShotAgentSessionMap.get(deviceId); - if (null == agentSession || !agentSession.isState()) { - AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId); - if (null == currentDevice) { - throw new ExecuteException("当前设备不在线"); - } - 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); - AdbDevice currentDevice = AndroidDeviceManager.getInstance().getCurrentDevice(deviceId); - if (null == currentDevice) { - throw new ExecuteException("当前设备不在线"); + AndroidAgent androidAgent = screenShotAgentMap.get(deviceId); + if (null == androidAgent) { + AdbDevice currentDevice = null; + ArrayList adbDevices = adb.listDevices(); + if (!CollectionUtils.isEmpty(adbDevices)) { + for (AdbDevice adbDevice : adbDevices) { + if (deviceId.equals(adbDevice.getSerial())) { + currentDevice = adbDevice; + break; + } } - agentSession = new AndroidAgentSession(currentDevice, false); - agentSession.start(); - screenShotAgentSessionMap.put(deviceId, agentSession); - } else { - logger.debug("设备【{}】当前使用的截图的session还能用,继续使用。。。。。",deviceId); } + if (null == currentDevice) { + logger.warn("设备【{}】不在线。。。。。",deviceId); + throw new ExecuteException("截图失败,当前设备不在线"); + } + logger.warn("设备【{}】没有androidAgent创建一个。。。。。",deviceId); + androidAgent = new AndroidAgent(adb, currentDevice); + screenShotAgentMap.put(deviceId, androidAgent); + } else { + logger.warn("设备【{}】已经存在androidAgent。。。。。",deviceId); } - byte[] screenShotData = agentSession.send(TakeScreenshotCommand.getInstance()); - if (null != screenShotData && screenShotData.length > 0) { //截图 - logger.debug("收到手机【{}】截图,大小:{}", deviceId, screenShotData.length); + byte[] screenShotData = androidAgent.takeScreenshot(); + if (null != screenShotData && screenShotData.length > 0) { + logger.debug("收到手机【{}】截图,大小:{}",deviceId,screenShotData.length); File tmpPicDir = new File(System.getProperty("user.dir")+"/tempPic"); if (!tmpPicDir.exists()) { - tmpPicDir.mkdir(); + tmpPicDir.mkdirs(); } String tmpPicPath = tmpPicDir.getAbsolutePath() + "/" + deviceId + "_" + System.currentTimeMillis() + ".png"; tmpPicFile = new File(tmpPicPath); - try (FileOutputStream fos = new FileOutputStream(tmpPicFile)){ + try (FileOutputStream fos = new FileOutputStream(tmpPicFile)) { fos.write(screenShotData); }catch (Exception e) { logger.error("截图写入临时文件异常:",e); } } - } catch (Exception e) { - logger.error("设备【"+deviceId+"】截图异常", e); - }finally { - logger.debug("设备【{}】写到本地的图片大小:{}", deviceId, tmpPicFile != null ? tmpPicFile.length() : 0); + }catch (Exception e) { + logger.error("设备【"+deviceId+"】截图异常",e); } return tmpPicFile; }