diff --git a/pom.xml b/pom.xml index 796a6ce..43e59c4 100644 --- a/pom.xml +++ b/pom.xml @@ -68,6 +68,13 @@ 0.12.35 + + + net.lingala.zip4j + zip4j + 2.11.5 + + diff --git a/src/main/java/net/geedge/api/controller/APIController.java b/src/main/java/net/geedge/api/controller/APIController.java index 8d04d32..cad62e5 100644 --- a/src/main/java/net/geedge/api/controller/APIController.java +++ b/src/main/java/net/geedge/api/controller/APIController.java @@ -9,15 +9,17 @@ import net.geedge.api.entity.EnvApiYml; import net.geedge.api.util.AdbUtil; import net.geedge.api.util.CommandExec; import net.geedge.common.*; +import net.lingala.zip4j.ZipFile; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.model.enums.CompressionLevel; +import net.lingala.zip4j.model.enums.CompressionMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.*; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.zip.ZipEntry; @RestController @RequestMapping("/api/v1/env") @@ -298,11 +300,7 @@ public class APIController { } catch (Exception e) { log.error(e.getMessage()); - Map resultMap = T.MapUtil.builder() - .put("status", "error") - .build(); - Constant.PLAYBOOK_RUN_RESULT.put(id, resultMap); - return R.ok(); + throw new APIException(RCode.ERROR); } finally { T.FileUtil.del(destination); } @@ -316,11 +314,9 @@ public class APIController { if (T.StrUtil.isEmpty(id)) { throw new APIException(RCode.BAD_REQUEST); } - Map result = Constant.PLAYBOOK_RUN_RESULT.get(id); - if (T.MapUtil.isNotEmpty(result) && !T.MapUtil.getStr(result, "status").equals("running")){ - Constant.PLAYBOOK_RUN_RESULT.remove(id); - } - return R.ok().putData(result); + File statusFile = FileUtil.file(Constant.TEMP_PATH, id, "result.json"); + String status = T.FileUtil.readString(statusFile, "UTF-8"); + return R.ok().putData(status); } @@ -366,9 +362,22 @@ public class APIController { return name.endsWith(".log") || name.endsWith(".pcap"); } }); - T.ZipUtil.zip(zipFile, true, files); - T.ResponseUtil.downloadFile(response,zipFile.getName(), T.FileUtil.readBytes(zipFile)); + ZipFile zip = null; + try { + zip = new ZipFile(zipFile); + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(CompressionMethod.DEFLATE); // 压缩方法 + parameters.setCompressionLevel(CompressionLevel.FASTEST); // 压缩级别,选项有 FASTEST、ULTRA 等 + + // 添加文件到 ZIP + for (File file : files) { + zip.addFile(file, parameters); + } + T.ResponseUtil.downloadFile(response, zipFile.getName(), T.FileUtil.readBytes(zipFile.getPath())); + } finally { + zip.close(); + } } public class PlaybookRunnable extends Thread { @@ -391,6 +400,9 @@ public class APIController { @Override public void run() { File logFile = FileUtil.file(Constant.TEMP_PATH, tid, "result.log"); + File statusFile = FileUtil.file(Constant.TEMP_PATH, tid, "result.json"); + AdbUtil.CommandResult tcpdumpPackage = null; + AdbUtil.CommandResult tcpdumpAll = null; try { T.FileUtil.appendString(String.format("Running with %s:%s Android Simulator \n", envApiYml.getAdb().getHost(), envApiYml.getAdb().getPort()), logFile, "UTF-8"); @@ -399,69 +411,94 @@ public class APIController { Map resultMap = T.MapUtil.builder() .put("status", "running") .build(); - Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap); + T.FileUtil.writeString(T.JSONUtil.toJsonStr(resultMap), statusFile, "UTF-8"); - // 1. install apk + // install apk AdbUtil.CommandResult install = adbUtil.install(apkFile.getAbsolutePath(), true, true); if (0 != install.exitCode()) { T.FileUtil.appendString(String.format("ERROR: Install apk failed: exit code %s \n", install.exitCode()), logFile, "UTF-8"); throw new APIException(install.output()); } - // 2. star tcpdump - AdbUtil.CommandResult startTcpdump = adbUtil.startTcpdump(packageName); - if (0 != startTcpdump.exitCode()) { - T.FileUtil.appendString(String.format("ERROR: Start tcpdump failed: exit code %s \n", startTcpdump.exitCode()), logFile, "UTF-8"); - throw new APIException("exec tcpdump error"); + // clear app data + AdbUtil.CommandResult clearData = adbUtil.clearAppData(packageName); + if (0 != clearData.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Clear %s data error: exit code %s \n", packageName, install.exitCode()), logFile, "UTF-8"); + throw new APIException(clearData.output()); } - // 3. exec playbook - AdbUtil.CommandResult execResult = adbUtil.execPlaybook(playbookDir.getPath(), logFile); - if (0 != execResult.exitCode()) { - // exec playbook error, stop tcpdump and delete pcap - T.FileUtil.appendString(String.format("ERROR: Exec playbook failed: exit code %s \n", execResult.exitCode()), logFile, "UTF-8"); - AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output()); - adbUtil.execShellCommand(String.format("shell rm -rf %s", stopTcpdump.output())); - throw new APIException("exec playbook error"); + // star tcpdump: package name + tcpdumpPackage = adbUtil.startTcpdump(packageName); + if (0 != tcpdumpPackage.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Start tcpdump %s failed: exit code %s \n", packageName, tcpdumpPackage.exitCode()), logFile, "UTF-8"); + throw new APIException(String.format("tcpdump %s error", packageName)); } - // 4. stop tcpdump - AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output()); - if (0 != stopTcpdump.exitCode()) { - T.FileUtil.appendString(String.format("ERROR: Stop tcpdump failed: exit code %s \n", stopTcpdump.exitCode()), logFile, "UTF-8"); - throw new APIException(stopTcpdump.output()); + // star tcpdump: all + tcpdumpAll = adbUtil.startTcpdump(T.StrUtil.EMPTY); + if (0 != tcpdumpAll.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Start tcpdump all failed: exit code %s \n", tcpdumpAll.exitCode()), logFile, "UTF-8"); + throw new APIException("tcpdump all error"); } - // 5. pull pcap file - String filePath = stopTcpdump.output(); - File localPcapFile = T.FileUtil.file(Constant.TEMP_PATH, tid, startTcpdump.output() + ".pcap"); - if (T.StrUtil.isEmpty(filePath)) { - throw new APIException(RCode.NOT_EXISTS); + // exec playbook + AdbUtil.CommandResult airtestResult = adbUtil.execPlaybook(playbookDir.getPath(), logFile); + if (0 != airtestResult.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Exec playbook failed: exit code %s \n", airtestResult.exitCode()), logFile, "UTF-8"); + throw new APIException("playbook exec error"); } - AdbUtil.CommandResult pull = adbUtil.pull(filePath, localPcapFile.getAbsolutePath()); - if (0 != pull.exitCode()) { - T.FileUtil.appendString(String.format("ERROR: Pull pcap file failed: exit code %s \n", pull.exitCode()), logFile, "UTF-8"); - throw new APIException(pull.output()); - } + // stop package tcpdump + stopTcpdump(tcpdumpPackage, logFile, packageName); - // 6. delete android pcap - adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath)); + // stop all tcpdump + stopTcpdump(tcpdumpAll, logFile, T.StrUtil.EMPTY); resultMap = T.MapUtil.builder() .put("status", "done") .build(); - Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap); + T.FileUtil.writeString(T.JSONUtil.toJsonStr(resultMap), statusFile, "UTF-8"); } catch (Exception e) { log.error(e); Map resultMap = T.MapUtil.builder() .put("status", "error") .build(); - Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap); + T.FileUtil.writeString(T.JSONUtil.toJsonStr(resultMap), statusFile, "UTF-8"); + + AdbUtil.CommandResult packageTcpdump = adbUtil.stopTcpdump(tcpdumpPackage.output()); + adbUtil.execShellCommand(String.format("shell rm -rf %s", packageTcpdump.output())); + AdbUtil.CommandResult allTcpdump = adbUtil.stopTcpdump(tcpdumpAll.output()); + adbUtil.execShellCommand(String.format("shell rm -rf %s", allTcpdump.output())); } finally { adbUtil.stopApp(packageName); T.FileUtil.appendString(String.format("Job succeeded"), logFile, "UTF-8"); } } + + private void stopTcpdump(AdbUtil.CommandResult tcpdump, File logFile, String packageName) { + // stop tcpdump + AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(tcpdump.output()); + if (0 != stopTcpdump.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Stop tcpdump failed: exit code %s \n", stopTcpdump.exitCode()), logFile, "UTF-8"); + throw new APIException(stopTcpdump.output()); + } + + // pull pcap file + String filePath = stopTcpdump.output(); + packageName = T.StrUtil.isEmpty(packageName) ? "all" : packageName; + File localPcapFile = T.FileUtil.file(Constant.TEMP_PATH, tid, String.format("%s-%s%s", tcpdump.output(), packageName, ".pcap")); + if (T.StrUtil.isEmpty(filePath)) { + throw new APIException(RCode.NOT_EXISTS); + } + + AdbUtil.CommandResult pull = adbUtil.pull(filePath, localPcapFile.getAbsolutePath()); + if (0 != pull.exitCode()) { + T.FileUtil.appendString(String.format("ERROR: Pull pcap file failed: exit code %s \n", pull.exitCode()), logFile, "UTF-8"); + throw new APIException(pull.output()); + } + + // delete android pcap + adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath)); + } } } \ No newline at end of file diff --git a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java index 575a809..e0b6b12 100644 --- a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java +++ b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java @@ -218,4 +218,12 @@ public class AdbCommandBuilder { this.command.add(packageName); return this; } + + public AdbCommandBuilder buildClearAppDateCommand(String packageName) { + this.command.add("shell"); + this.command.add("pm"); + this.command.add("clear"); + this.command.add(packageName); + return this; + } } \ No newline at end of file diff --git a/src/main/java/net/geedge/api/util/AdbUtil.java b/src/main/java/net/geedge/api/util/AdbUtil.java index 0e09fab..0030261 100644 --- a/src/main/java/net/geedge/api/util/AdbUtil.java +++ b/src/main/java/net/geedge/api/util/AdbUtil.java @@ -819,6 +819,15 @@ public class AdbUtil { log.info("[deleteAcl] [protocol: {}] [ip: {}] [port: {}] [result: {}]", protocol, ip, port, result); } + public CommandResult clearAppData(String packageName) { + String result = commandExec.exec(AdbCommandBuilder.builder() + .serial(this.getSerial()) + .buildClearAppDateCommand(packageName) + .build()); + log.info("[clearAppData] [packageName: {}]", packageName); + return new CommandResult(T.StrUtil.containsAny(result, "Success") ? 0 : 1, result); + } + /** * flushAcl * iptables -F ASW_OUTPUT