package net.geedge.api.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.log.Log; import net.geedge.api.entity.EnvApiYml; import net.geedge.common.APIException; import net.geedge.common.Constant; import net.geedge.common.RCode; import net.geedge.common.T; import java.io.File; import java.util.List; import java.util.Map; public class PlaybookRunnable implements Runnable { private final static Log log = Log.get(); private AdbUtil adbUtil; private EnvApiYml envApiYml; private String tid; private File apkFile; private String packageName; private File scriptPath; private String type; private boolean reInstall; private boolean clearCache; private boolean unInstall; private boolean interrupt; public PlaybookRunnable(EnvApiYml envApiYml, File apkFile, File scriptPath, String tid, String packageName, String type, Boolean reInstall, Boolean clearCache, Boolean unInstall) { this.envApiYml = envApiYml; this.tid = tid; this.apkFile = apkFile; this.packageName = packageName; this.scriptPath = scriptPath; this.type = type; this.reInstall = reInstall; this.clearCache = clearCache; this.unInstall = unInstall; this.interrupt = false; } @Override public void run() { Thread.currentThread().setName("exec-playbook-thread-" + tid); Constant.ACTIVE_TASKS.add(this); 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 { Map resultMap = T.MapUtil.builder() .put("status", "running") .build(); T.FileUtil.writeString(T.JSONUtil.toJsonStr(resultMap), statusFile, "UTF-8"); if (interrupt) return; T.FileUtil.appendString(String.format("Running with %s:%s Android Simulator \n", envApiYml.getAdb().getHost(), envApiYml.getAdb().getPort()), logFile, "UTF-8"); adbUtil = new AdbUtil(envApiYml.getAdb(), new CommandExec(logFile)); // Check if the package is installed if (interrupt) return; boolean packageIsInstall = adbUtil.findPackageInstall(packageName); if (packageIsInstall) { if (!reInstall) { // install apk if (interrupt) return; 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()); } } } else { // install apk if (interrupt) return; 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()); } } //Close other apps if (interrupt) return; List packageNameList = adbUtil.findPackageNameList(); this.closeApp(packageNameList, packageName); // clear app data if (interrupt) return; if (clearCache) { 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, clearData.exitCode()), logFile, "UTF-8"); throw new APIException(clearData.output()); } } // Launch the app if (interrupt) return; adbUtil.startApp(packageName); // star tcpdump: package name if (interrupt) return; 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)); } // star tcpdump: all if (interrupt) return; 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"); } // exec playbook if (interrupt) return; AdbUtil.CommandResult airtestResult = adbUtil.execPlaybook(scriptPath.getPath(), tid, packageName, type, 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"); } // stop package tcpdump if (interrupt) return; stopTcpdump(tcpdumpPackage, logFile, packageName); // stop all tcpdump if (interrupt) return; stopTcpdump(tcpdumpAll, logFile, T.StrUtil.EMPTY); resultMap = T.MapUtil.builder() .put("status", "done") .build(); 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(); T.FileUtil.writeString(T.JSONUtil.toJsonStr(resultMap), statusFile, "UTF-8"); } finally { if (T.StrUtil.isNotEmpty(tcpdumpPackage.output())) { AdbUtil.CommandResult packageTcpdump = adbUtil.stopTcpdump(tcpdumpPackage.output()); adbUtil.execShellCommand(String.format("shell rm -rf %s", packageTcpdump.output())); } if (T.StrUtil.isNotEmpty(tcpdumpAll.output())) { AdbUtil.CommandResult allTcpdump = adbUtil.stopTcpdump(tcpdumpAll.output()); adbUtil.execShellCommand(String.format("shell rm -rf %s", allTcpdump.output())); } this.closeApp(ListUtil.empty(), packageName); if (unInstall) { adbUtil.uninstall(packageName); } T.FileUtil.appendString(String.format("Job execution ends"), logFile, "UTF-8"); Constant.ACTIVE_TASKS.remove(this); } } public void interrupt() { this.interrupt = true; adbUtil.setInterrupt(true); } private void closeApp(List packageNameList, String packageName) { if (CollUtil.isNotEmpty(packageNameList)) { for (String name : packageNameList) { adbUtil.stopApp(name); } } adbUtil.stopApp(packageName); } 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)); } }