summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/net/geedge/api/controller/APIController.java193
-rw-r--r--src/main/java/net/geedge/api/util/AdbUtil.java153
2 files changed, 220 insertions, 126 deletions
diff --git a/src/main/java/net/geedge/api/controller/APIController.java b/src/main/java/net/geedge/api/controller/APIController.java
index 0b7342d..5df1bad 100644
--- a/src/main/java/net/geedge/api/controller/APIController.java
+++ b/src/main/java/net/geedge/api/controller/APIController.java
@@ -12,10 +12,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
+import java.io.*;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -62,7 +61,7 @@ public class APIController {
File tempFile = T.FileUtil.file(Constant.TEMP_PATH, fileName);
try {
- AdbUtil.CommandResult result = adbUtil.pull(filePath, tempFile.getAbsolutePath());
+ AdbUtil.CommandResult result = adbUtil.pull(filePath, tempFile.getAbsolutePath(), false);
if (0 != result.exitCode()) {
throw new APIException(result.output());
}
@@ -105,7 +104,7 @@ public class APIController {
tempFile = T.FileUtil.file(Constant.TEMP_PATH, file.getOriginalFilename());
file.transferTo(tempFile);
- AdbUtil.CommandResult result = adbUtil.install(tempFile.getAbsolutePath(), true, true);
+ AdbUtil.CommandResult result = adbUtil.install(tempFile.getAbsolutePath(), true, true, false);
if (0 != result.exitCode()) {
throw new APIException(result.output());
}
@@ -116,7 +115,7 @@ public class APIController {
}
if (T.StrUtil.isNotEmpty(path)) {
- AdbUtil.CommandResult result = adbUtil.install(path, true, true);
+ AdbUtil.CommandResult result = adbUtil.install(path, true, true, false);
if (0 != result.exitCode()) {
throw new APIException(result.output());
}
@@ -141,7 +140,7 @@ public class APIController {
@PostMapping("/pcap")
public R startTcpdump(@RequestParam(required = false, defaultValue = "") String packageName) {
- AdbUtil.CommandResult result = adbUtil.startTcpdump(packageName);
+ AdbUtil.CommandResult result = adbUtil.startTcpdump(packageName, false);
if (0 != result.exitCode()) {
throw new APIException("exec tcpdump error");
}
@@ -150,9 +149,9 @@ public class APIController {
@DeleteMapping("/pcap")
public synchronized void stopTcpdump(@RequestParam String id,
- @RequestParam(required = false, defaultValue = "false") Boolean returnFile,
- HttpServletResponse response) throws IOException {
- AdbUtil.CommandResult result = adbUtil.stopTcpdump(id);
+ @RequestParam(required = false, defaultValue = "false") Boolean returnFile,
+ HttpServletResponse response) throws IOException {
+ AdbUtil.CommandResult result = adbUtil.stopTcpdump(id, false);
if (0 != result.exitCode()) {
throw new APIException(result.output());
}
@@ -166,7 +165,7 @@ public class APIController {
if (T.StrUtil.isEmpty(filePath)) {
throw new APIException(RCode.NOT_EXISTS);
}
- AdbUtil.CommandResult pulled = adbUtil.pull(filePath, tempFile.getAbsolutePath());
+ AdbUtil.CommandResult pulled = adbUtil.pull(filePath, tempFile.getAbsolutePath(), false);
if (0 != pulled.exitCode()) {
throw new APIException(pulled.output());
}
@@ -181,7 +180,7 @@ public class APIController {
} finally {
if (T.StrUtil.isNotEmpty(filePath)) {
// remove pcap file
- adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath));
+ adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath), false);
}
}
}
@@ -254,53 +253,112 @@ public class APIController {
}
@PostMapping("/playbook")
- public R execPlaybook(@RequestParam("files") MultipartFile[] files, @RequestParam("packageName") String packageName) throws IOException {
- // save zip and apk
- String tid = T.StrUtil.uuid();
- File appFile = null;
+ public R execPlaybook(@RequestParam("files") MultipartFile file,
+ @RequestParam("packageName") String packageName,
+ @RequestParam("id") String id) {
+ File apkFile = null;
File playbookAirDir = null;
- for (MultipartFile file : files) {
- if (T.FileUtil.extName(file.getOriginalFilename()).equals("zip")) {
- File playbookFile = T.FileUtil.file(Constant.TEMP_PATH, tid, file.getOriginalFilename());
- T.FileUtil.writeBytes(file.getInputStream().readAllBytes(), playbookFile);
- File playbookDir = T.FileUtil.file(Constant.TEMP_PATH, tid);
- T.ZipUtil.unzip(playbookFile, playbookDir);
- playbookAirDir = Arrays.stream(playbookDir.listFiles(new FileFilter() {
- @Override
- public boolean accept(File pathname) {
- return pathname.getName().endsWith(".air");
- }
- })).findFirst().get();
- } else {
- appFile = T.FileUtil.file(Constant.TEMP_PATH, tid, file.getOriginalFilename());
- T.FileUtil.writeBytes(file.getInputStream().readAllBytes(), appFile);
- }
+ File destination = null;
+ try {
+ File playbookDir = T.FileUtil.file(Constant.TEMP_PATH, id);
+ destination = T.FileUtil.file(Constant.TEMP_PATH, id, file.getName());
+ T.FileUtil.writeBytes(file.getInputStream().readAllBytes(), destination);
+
+ // unzip file
+ T.ZipUtil.unzip(destination, playbookDir);
+
+ // apk
+ apkFile = Arrays.stream(playbookDir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".apk");
+ }
+ })).findFirst().get();
+
+ // playbook zip
+ File playbook = Arrays.stream(playbookDir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".zip") && !name.equals(file.getName());
+ }
+ })).findFirst().get();
+
+ // unzip playbook zip
+ T.ZipUtil.unzip(playbook, playbookDir);
+ playbookAirDir = Arrays.stream(playbookDir.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return pathname.getName().endsWith(".air");
+ }
+ })).findFirst().get();
+
+ } 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();
+ } finally {
+ T.FileUtil.del(destination);
}
- PlaybookRunnable playbookRunnable = new PlaybookRunnable(adbUtil, appFile, playbookAirDir, tid, packageName);
+ PlaybookRunnable playbookRunnable = new PlaybookRunnable(adbUtil, apkFile, playbookAirDir, id, packageName);
ThreadUtil.execAsync(playbookRunnable);
- return R.ok().putData("tid", tid);
+ return R.ok();
}
@GetMapping("/playbook/{id}")
- public void getExecPlaybookResult(@PathVariable("id") String id, HttpServletResponse response) throws IOException {
+ public R checkJobResult(@PathVariable("id") String id){
if (T.StrUtil.isEmpty(id)) {
throw new APIException(RCode.BAD_REQUEST);
}
Map result = Constant.PLAYBOOK_RUN_RESULT.get(id);
- if (result != null) {
- String status = T.MapUtil.getStr(result, "status");
- if (T.MapUtil.getStr(result, "status").equals("done")) {
- String artifact = T.MapUtil.getStr(result, "artifact");
- File pcapFile = T.FileUtil.file(artifact);
- Constant.PLAYBOOK_RUN_RESULT.remove(id);
- T.ResponseUtil.downloadFile(response, pcapFile.getName(), T.FileUtil.readBytes(pcapFile));
- } else if (status.equals("error")) {
- Constant.PLAYBOOK_RUN_RESULT.remove(id);
- response.getWriter().write(T.JSONUtil.toJsonStr(R.ok().putData(result)));
- } else {
- response.getWriter().write(T.JSONUtil.toJsonStr(R.ok().putData(result)));
- }
+ return R.ok().putData(result);
+ }
+
+
+ @GetMapping("/playbook/{id}/log")
+ public R getJobResultLog(@PathVariable("id") String id,
+ @RequestParam("offset") Integer offset){
+ if (T.StrUtil.isEmpty(id)) {
+ throw new APIException(RCode.BAD_REQUEST);
}
+ // log file
+ File logFile = T.FileUtil.file(Constant.TEMP_PATH, id, "result.log");
+ HashMap<Object, Object> result = T.MapUtil.newHashMap(false);
+ try (RandomAccessFile raf = new RandomAccessFile(logFile, "r")) {
+ raf.seek(offset);
+ byte[] bytes = new byte[(int)raf.length() - offset];
+ raf.readFully(bytes);
+ String content = new String(bytes);
+ result.put("content", content);
+ result.put("length", bytes.length);
+ result.put("offset", offset + bytes.length);
+ } catch (IOException e) {
+ log.error("getJobResultLog error", e);
+ throw new APIException(RCode.ERROR);
+ }
+ return R.ok().putData(result);
+ }
+
+
+ @GetMapping("/playbook/{id}/artifact")
+ public void getJobResultArtifact(@PathVariable("id") String id, HttpServletResponse response) throws IOException {
+ if (T.StrUtil.isEmpty(id)) {
+ throw new APIException(RCode.BAD_REQUEST);
+ }
+ // job dir
+ File jobResult = T.FileUtil.file(Constant.TEMP_PATH, id);
+ File zipFile = T.FileUtil.file(Constant.TEMP_PATH, T.StrUtil.concat(true, id, ".zip"));
+ File[] files = jobResult.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".log") || name.endsWith(".pcap");
+ }
+ });
+ T.ZipUtil.zip(zipFile, true, files);
+ T.ResponseUtil.downloadFile(response,zipFile.getName(), T.FileUtil.readBytes(zipFile));
+
}
public class PlaybookRunnable extends Thread {
@@ -321,37 +379,47 @@ public class APIController {
@Override
public void run() {
+ File logFile = FileUtil.file(Constant.TEMP_PATH, tid, "result.log");
try {
+
+ adbUtil.setLogFile(logFile);
+
Map resultMap = T.MapUtil.builder()
.put("status", "running")
.build();
Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
+ T.FileUtil.appendString(String.format("Running with %s Android Simulator \n", adbUtil.getSerial()), logFile, "UTF-8");
+
// 1. install apk
- AdbUtil.CommandResult install = adbUtil.install(apkFile.getAbsolutePath(), true, true);
+ AdbUtil.CommandResult install = adbUtil.install(apkFile.getAbsolutePath(), true, 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);
+ AdbUtil.CommandResult startTcpdump = adbUtil.startTcpdump(packageName, true);
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");
}
// 3. exec playbook
- AdbUtil.CommandResult execResult = adbUtil.execPlaybook(playbookDir.getPath());
- T.FileUtil.writeString(execResult.output(), FileUtil.file(Constant.TEMP_PATH, tid, "log", "log.txt"), "UTF-8");
+ AdbUtil.CommandResult execResult = adbUtil.execPlaybook(playbookDir.getPath(), true);
if (0 != execResult.exitCode()) {
// exec playbook error, stop tcpdump and delete pcap
- AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output());
- adbUtil.execShellCommand(String.format("shell rm -rf %s", stopTcpdump.output()));
+ 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(), true);
+ adbUtil.execShellCommand(String.format("shell rm -rf %s", stopTcpdump.output()), true);
throw new APIException("exec playbook error");
}
// 4. stop tcpdump
- AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output());
+ AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output(), true);
+ T.FileUtil.appendString(T.StrUtil.concat(true, stopTcpdump.output(), "\n"), logFile, "UTF-8");
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());
}
@@ -361,29 +429,30 @@ public class APIController {
if (T.StrUtil.isEmpty(filePath)) {
throw new APIException(RCode.NOT_EXISTS);
}
- AdbUtil.CommandResult pull = adbUtil.pull(filePath, localPcapFile.getAbsolutePath());
+
+ AdbUtil.CommandResult pull = adbUtil.pull(filePath, localPcapFile.getAbsolutePath(), true);
+ T.FileUtil.appendString(T.StrUtil.concat(true, pull.output(), "\n"), logFile, "UTF-8");
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());
}
// 6. delete android pcap
- adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath));
+ adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath), true);
resultMap = T.MapUtil.builder()
.put("status", "done")
- .put("artifact", localPcapFile.getAbsolutePath())
.build();
Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
- }catch (Exception e) {
+ } catch (Exception e) {
log.error(e);
Map resultMap = T.MapUtil.builder()
.put("status", "error")
.build();
Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
} finally {
- adbUtil.stopApp(packageName);
- //T.FileUtil.del(apkFile);
- //T.FileUtil.clean(playbookDir);
+ adbUtil.stopApp(packageName, true);
+ T.FileUtil.appendString(String.format("Job succeeded"), logFile, "UTF-8");
}
}
}
diff --git a/src/main/java/net/geedge/api/util/AdbUtil.java b/src/main/java/net/geedge/api/util/AdbUtil.java
index b8aecce..7cb0d20 100644
--- a/src/main/java/net/geedge/api/util/AdbUtil.java
+++ b/src/main/java/net/geedge/api/util/AdbUtil.java
@@ -15,6 +15,7 @@ import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class AdbUtil {
@@ -32,8 +33,14 @@ public class AdbUtil {
private Integer vncPort;
+ private File logFile;
+
private ExecutorService threadPool;
+ public void setLogFile(File logFile) {
+ this.logFile = logFile;
+ }
+
public String getSerial() {
return T.StrUtil.isNotEmpty(this.serial) ? serial : String.format("%s:%s", this.host, this.port);
}
@@ -86,7 +93,7 @@ public class AdbUtil {
}
} else {
// remote
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile ,false).exec(AdbCommandBuilder.builder()
.buildConnectCommand(this.host, this.port)
.build());
log.info("[connect] [result: {}]", result);
@@ -104,7 +111,7 @@ public class AdbUtil {
*/
public void init(boolean install) {
// adb root
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile ,false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildRootCommand()
.build()
@@ -113,26 +120,26 @@ public class AdbUtil {
if (install) {
// install droidVNC NG
- CommandResult installed = this.install(DEFAULT_DROIDVNC_NG_APK_PATH, true, true);
+ CommandResult installed = this.install(DEFAULT_DROIDVNC_NG_APK_PATH, true, true,false);
log.info("[init] [install droidVNC NG] [result: {}]", installed);
// 上传默认配置
- this.execShellCommand("shell mkdir -p /storage/emulated/0/Android/data/net.christianbeier.droidvnc_ng/files");
+ this.execShellCommand("shell mkdir -p /storage/emulated/0/Android/data/net.christianbeier.droidvnc_ng/files",false);
this.push(DEFAULT_DROIDVNC_NG_DEFAULTS_JSON_PATH, "/storage/emulated/0/Android/data/net.christianbeier.droidvnc_ng/files/defaults.json");
// 无障碍权限
- this.execShellCommand("shell settings put secure enabled_accessibility_services net.christianbeier.droidvnc_ng/.InputService:$(settings get secure enabled_accessibility_services)");
+ this.execShellCommand("shell settings put secure enabled_accessibility_services net.christianbeier.droidvnc_ng/.InputService:$(settings get secure enabled_accessibility_services)",false);
// 存储空间权限
- this.execShellCommand("shell pm grant net.christianbeier.droidvnc_ng android.permission.WRITE_EXTERNAL_STORAGE");
+ this.execShellCommand("shell pm grant net.christianbeier.droidvnc_ng android.permission.WRITE_EXTERNAL_STORAGE",false);
// 屏幕录制权限
- this.execShellCommand("shell appops set net.christianbeier.droidvnc_ng PROJECT_MEDIA allow");
+ this.execShellCommand("shell appops set net.christianbeier.droidvnc_ng PROJECT_MEDIA allow",false);
// ACTION_STOP
- this.execShellCommand("shell am start-foreground-service -n net.christianbeier.droidvnc_ng/.MainService -a net.christianbeier.droidvnc_ng.ACTION_STOP --es net.christianbeier.droidvnc_ng.EXTRA_ACCESS_KEY d042e2b5d5f348588a4e1a243eb7a9a0");
+ this.execShellCommand("shell am start-foreground-service -n net.christianbeier.droidvnc_ng/.MainService -a net.christianbeier.droidvnc_ng.ACTION_STOP --es net.christianbeier.droidvnc_ng.EXTRA_ACCESS_KEY d042e2b5d5f348588a4e1a243eb7a9a0",false);
}
// ACTION_START
- this.execShellCommand("shell am start-foreground-service -n net.christianbeier.droidvnc_ng/.MainService -a net.christianbeier.droidvnc_ng.ACTION_START --es net.christianbeier.droidvnc_ng.EXTRA_ACCESS_KEY d042e2b5d5f348588a4e1a243eb7a9a0");
+ this.execShellCommand("shell am start-foreground-service -n net.christianbeier.droidvnc_ng/.MainService -a net.christianbeier.droidvnc_ng.ACTION_START --es net.christianbeier.droidvnc_ng.EXTRA_ACCESS_KEY d042e2b5d5f348588a4e1a243eb7a9a0",false);
// 添加自定义链
this.addAswOutputChain();
@@ -172,7 +179,7 @@ public class AdbUtil {
m.put("type", type);
// check root
- String checkRootResult = CommandExec.exec(AdbCommandBuilder.builder()
+ String checkRootResult = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildCheckRootCommand()
.build()
@@ -188,7 +195,7 @@ public class AdbUtil {
* @return
*/
private AdbDevice getAdbDevice() {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.buildDevicesCommand()
.build()
);
@@ -213,7 +220,7 @@ public class AdbUtil {
* @return
*/
private Map<String, String> getProp() {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildGetpropCommand()
.build()
@@ -230,7 +237,7 @@ public class AdbUtil {
}
// 分辨率 Physical size: 1440x3040
- String wmSize = CommandExec.exec(AdbCommandBuilder.builder()
+ String wmSize = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildWmSizeCommand()
.build()
@@ -244,7 +251,7 @@ public class AdbUtil {
* md5sum
*/
private CommandResult md5sum(String path) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildMd5sumCommand(path)
.build()
@@ -262,7 +269,7 @@ public class AdbUtil {
* 0 success; !0 failed
*/
public CommandResult push(String local, String remote) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildPushCommand(local, remote)
.build()
@@ -275,8 +282,8 @@ public class AdbUtil {
* pull
* 0 success; !0 failed
*/
- public CommandResult pull(String remote, String local) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ public CommandResult pull(String remote, String local, boolean isRecordLog) {
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildPullCommand(remote, local)
.build()
@@ -291,7 +298,7 @@ public class AdbUtil {
* stat filename
*/
public List<Map> listDir(String path) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildLsDirCommand(path)
.build()
@@ -329,7 +336,7 @@ public class AdbUtil {
String statCommand = "shell stat -c \"'%N %A %g %u %s %a %X %Y'\" " + statFilePath;
futureList.add(
CompletableFuture.supplyAsync(() -> {
- String statResult = CommandExec.exec(AdbCommandBuilder.builder()
+ String statResult = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(statCommand.replaceAll("\\\\", "/"))
.build()
@@ -390,7 +397,7 @@ public class AdbUtil {
* @return
*/
public List<Map> listApp(String arg) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildPmListPackagesCommand(arg)
.build()
@@ -406,7 +413,7 @@ public class AdbUtil {
String packageName = T.StrUtil.trim(line.substring(prefix.length()));
if (T.StrUtil.equals(DEFAULT_DROIDVNC_NG_PKG_NAME, packageName)) continue;
- String dumpsysResult = CommandExec.exec(AdbCommandBuilder.builder()
+ String dumpsysResult = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell dumpsys package " + packageName)
.build()
@@ -430,7 +437,7 @@ public class AdbUtil {
String md5Value = md5sumRes.output();
File localApk = T.FileUtil.file(Constant.TEMP_PATH, md5Value + ".apk");
if (!T.FileUtil.exist(localApk)) {
- CommandResult pulled = this.pull(finalApkPath, localApk.getAbsolutePath());
+ CommandResult pulled = this.pull(finalApkPath, localApk.getAbsolutePath(), false);
if (0 != pulled.exitCode()) {
log.warn("[listApp] [pull apk error] [pkg: {}]", packageName);
return null;
@@ -487,12 +494,12 @@ public class AdbUtil {
* install app
* adb install apk
*/
- public CommandResult install(String localFilePath, boolean isDebugApk, boolean isReInstall) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ public CommandResult install(String localFilePath, boolean isDebugApk, boolean isReInstall, boolean isRecordLog) {
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildInstallCommand(localFilePath, isDebugApk, isReInstall)
- .build()
- );
+ .build());
+
log.info("[install] [localFilePath: {}] [isDebugApk: {}] [isReInstall: {}] [result: {}]", localFilePath, isDebugApk, isReInstall, result);
return new CommandResult(T.StrUtil.containsAny(result, "Success") ? 0 : 1, result);
}
@@ -502,7 +509,7 @@ public class AdbUtil {
* adb uninstall package_name
*/
public CommandResult uninstall(String packageName) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildUnInstallCommand(packageName)
.build()
@@ -515,8 +522,8 @@ public class AdbUtil {
* stop app
* adb shell am force-stop package_name
*/
- public CommandResult stopApp(String packageName) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ public CommandResult stopApp(String packageName, boolean isRecordLog) {
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildStopAppCommand(packageName)
.build()
@@ -532,13 +539,13 @@ public class AdbUtil {
@Deprecated
private void cleanIptables() {
// Delete all rules in chain or all chains
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell iptables -F")
.build()
);
// Delete user-defined chain
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell iptables -X")
.build()
@@ -549,7 +556,7 @@ public class AdbUtil {
* list tcpdump
*/
public List<Map> listTcpdump() {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"ps -ef | grep tcpdump | grep -v grep | grep capture_ | awk '{print $NF}' \""))
.build());
@@ -584,11 +591,11 @@ public class AdbUtil {
* start Tcpdump
* tcpdump pcap
*/
- public CommandResult startTcpdump(String packageName) {
+ public CommandResult startTcpdump(String packageName, boolean isRecordLog) {
String taskId = T.IdUtil.fastSimpleUUID();
if (T.StrUtil.isNotEmpty(packageName)) {
log.info("[startTcpdump] [capture app package] [pkg: {}]", packageName);
- String dumpsysResult = CommandExec.exec(AdbCommandBuilder.builder()
+ String dumpsysResult = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell dumpsys package " + packageName)
.build()
@@ -600,20 +607,20 @@ public class AdbUtil {
.map(s -> T.StrUtil.trim(s).replaceAll("userId=", ""))
.orElseThrow(() -> new APIException("Not found userId by package name. package name: " + packageName));
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -A OUTPUT -m owner --uid-owner %s -j CONNMARK --set-mark %s", userId, userId))
.build());
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -A INPUT -m connmark --mark %s -j NFLOG --nflog-group %s", userId, userId))
.build());
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -A OUTPUT -m connmark --mark %s -j NFLOG --nflog-group %s", userId, userId))
.build());
- String ruleList = CommandExec.exec(AdbCommandBuilder.builder()
+ String ruleList = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell iptables -L")
.build());
@@ -621,7 +628,7 @@ public class AdbUtil {
// pcap 格式:capture_{userId}_{pcakageName}_{taskId}.pcap
String pcapFilePath = "/data/local/tmp/capture_" + userId + "_" + packageName + "_" + taskId + ".pcap";
- CommandExec.execForProcess(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).execForProcess(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell tcpdump -i nflog:%s -w %s &", userId, pcapFilePath))
.build());
@@ -629,13 +636,13 @@ public class AdbUtil {
log.info("[startTcpdump] [capture all package]");
// pcap 格式:capture_all_{taskId}.pcap
String pcapFilePath = "/data/local/tmp/capture_all_" + taskId + ".pcap";
- CommandExec.execForProcess(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).execForProcess(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell tcpdump not port %s -w %s &", this.vncPort, pcapFilePath))
.build());
}
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"ps -ef | grep tcpdump | grep -v grep | grep %s | awk '{print $2}' \"", taskId))
.build());
@@ -647,8 +654,8 @@ public class AdbUtil {
* stop tcpdump
* kill -INT {pid}
*/
- public CommandResult stopTcpdump(String id) {
- String pcapFilePath = CommandExec.exec(AdbCommandBuilder.builder()
+ public CommandResult stopTcpdump(String id, boolean isRecordLog) {
+ String pcapFilePath = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"ps -ef | grep tcpdump | grep -v grep | grep %s | awk '{print $NF}' \"", id))
.build());
@@ -658,21 +665,21 @@ public class AdbUtil {
String[] split = T.FileUtil.mainName(pcapFilePath).split("_");
String userId = split[1];
log.info("[stopTcpdump] [remove iptables rule] [userId: {}]", userId);
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -D OUTPUT -m owner --uid-owner %s -j CONNMARK --set-mark %s", userId, userId))
.build());
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -D INPUT -m connmark --mark %s -j NFLOG --nflog-group %s", userId, userId))
.build());
- CommandExec.exec(AdbCommandBuilder.builder()
+ new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell iptables -D OUTPUT -m connmark --mark %s -j NFLOG --nflog-group %s", userId, userId))
.build());
}
}
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"ps -ef | grep tcpdump | grep -v grep | grep %s | awk '{print $2}' | xargs kill -INT \"", id))
.build());
@@ -681,7 +688,7 @@ public class AdbUtil {
for (int i = 0; i < 10; i++) {
T.ThreadUtil.sleep(500);
- String str = CommandExec.exec(AdbCommandBuilder.builder()
+ String str = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"ps -ef | grep tcpdump | grep -v grep | grep %s \"", id))
.build());
@@ -701,8 +708,8 @@ public class AdbUtil {
/**
* exec shell command
*/
- public void execShellCommand(String shellCmd) {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ public void execShellCommand(String shellCmd, boolean isRecordLog) {
+ String result = new CommandExec(logFile, isRecordLog).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(shellCmd)
.build());
@@ -713,7 +720,7 @@ public class AdbUtil {
* exec shell command
*/
public String execShellCommand(String cmd, Integer timeout){
- Process process = CommandExec.execForProcess(AdbCommandBuilder.builder()
+ Process process = new CommandExec(logFile, false).execForProcess(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand("shell " + cmd)
.build());
@@ -739,16 +746,16 @@ public class AdbUtil {
*/
private void addAswOutputChain() {
// name=ASW_OUTPUT
- this.execShellCommand("shell iptables -N ASW_OUTPUT");
+ this.execShellCommand("shell iptables -N ASW_OUTPUT", false);
- String outputChainResult = CommandExec.exec(AdbCommandBuilder.builder()
+ String outputChainResult = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildShellCommand(String.format("shell \"iptables -L OUTPUT --line-numbers | grep ASW_OUTPUT\""))
.build());
log.info("[addAswOutputChain] [ASW_OUTPUT in OUTPUT Chain] [result: {}]", outputChainResult);
if (T.StrUtil.isEmpty(outputChainResult)) {
// ASW_OUTPUT 添加到 OUTPUT 链中
- this.execShellCommand("shell iptables -A OUTPUT -j ASW_OUTPUT");
+ this.execShellCommand("shell iptables -A OUTPUT -j ASW_OUTPUT", false);
}
}
@@ -757,7 +764,7 @@ public class AdbUtil {
* iptables -nL ASW_OUTPUT --line-numbers
*/
public List<Map> listAcl() {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildIptablesLnRulesCommand("ASW_OUTPUT")
.build());
@@ -804,7 +811,7 @@ public class AdbUtil {
this.addAswOutputChain();
// add chain ruls
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildIptablesAddRuleCommand("ASW_OUTPUT", protocol, ip, port)
.build());
@@ -818,7 +825,7 @@ public class AdbUtil {
*/
public void deleteAcl(String protocol, String ip, String port) {
// add chain ruls
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildIptablesDelRuleCommand("ASW_OUTPUT", protocol, ip, port)
.build());
@@ -830,7 +837,7 @@ public class AdbUtil {
* iptables -F ASW_OUTPUT
*/
public CommandResult flushAcl() {
- String result = CommandExec.exec(AdbCommandBuilder.builder()
+ String result = new CommandExec(logFile, false).exec(AdbCommandBuilder.builder()
.serial(this.getSerial())
.buildIptablesFlushRuleCommand("ASW_OUTPUT")
.build());
@@ -851,30 +858,48 @@ public class AdbUtil {
return threadPool;
}
+
class CommandExec {
- public static String exec(List<String> command) {
+
+ private File logFile;
+ private boolean isRecordLog;
+
+ public String exec(List<String> command) {
String str = T.RuntimeUtil.execForStr(T.CharsetUtil.CHARSET_UTF_8, command.stream().toArray(String[]::new));
+ if (isRecordLog) {
+ T.FileUtil.appendString(T.StrUtil.concat(true, "$ ", command.stream().collect(Collectors.joining(" ")), "\n"), this.logFile, "UTF-8");
+ T.FileUtil.appendString(T.StrUtil.concat(true, str.stripTrailing(), "\n"), this.logFile, "UTF-8");
+ }
return str.stripTrailing();
}
- public static Process execForProcess(List<String> command) {
+ public Process execForProcess(List<String> command) {
Process process = T.RuntimeUtil.exec(command.stream().toArray(String[]::new));
return process;
}
+
+ public CommandExec(File logFile, boolean isRecordLog) {
+ this.logFile = logFile;
+ this.isRecordLog = isRecordLog;
+ }
}
- public CommandResult execPlaybook(String playbookPath) {
+ public CommandResult execPlaybook(String playbookPath, boolean isRecordLog) {
log.info("[execPlaybook] [begin!] [serial:{}]", this.getSerial());
- Process process = CommandExec.execForProcess(new AdbCommandBuilder("airtest")
+ List<String> command = new AdbCommandBuilder("airtest")
.buildRunPlaybook(playbookPath, this.getSerial())
- .build());
+ .build();
+ Process process = new CommandExec(logFile, isRecordLog).execForProcess(command);
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(() -> T.IoUtil.read(process.getInputStream(), T.CharsetUtil.CHARSET_UTF_8));
try {
int exitCode = process.waitFor();
String result = future.get(10, TimeUnit.SECONDS);
- log.info("[execPlaybook] [result: {}]", result);
+ if (isRecordLog){
+ T.FileUtil.appendString(T.StrUtil.concat(true, "$ ", command.stream().collect(Collectors.joining(" ")), "\n"), this.logFile, "UTF-8");
+ T.FileUtil.appendString(T.StrUtil.concat(true, result.stripTrailing(), "\n"), this.logFile, "UTF-8");
+ }
return new CommandResult(exitCode, result);
} catch (Exception e) {
process.destroyForcibly();