package com.duolebo.blyrobot.util import android.util.Log import com.duolebo.blyrobot.data.EmulateKey import java.io.BufferedReader import java.io.DataOutputStream import java.io.IOException import java.io.InputStreamReader object AdbUtil { const val TAG = "AdbUtil" const val SHELL = "sh" const val ROOT_SHELL = "su" const val LINE_BREAK = "\n" const val EXIT = "exit" fun checkRootPermission(): Boolean { val proc = getRootShell() return proc != null } fun getRootShell(): Process? { var proc: Process? = null try { proc = Runtime.getRuntime().exec(ROOT_SHELL) } catch (e: Exception) { e.printStackTrace() } return proc } fun exeCmdSync(cmd: String): Process? { Log.i(TAG, "exe cmd: $cmd") var proc: Process? = null try { proc = Runtime.getRuntime().exec(ROOT_SHELL) } catch (e: Exception) { e.printStackTrace() } return proc } fun exeCmdEcho(cmd: String, root: Boolean = false): CmdResult { val exeCommands = ArrayList() exeCommands.add(cmd) return exeCmdEcho(exeCommands, root) } fun exeCmdEcho(commands: ArrayList, root: Boolean = false): CmdResult { Log.i(TAG, "exe cmd echo: $commands") val exeCommands = ArrayList() exeCommands.addAll(commands) val result = sendCommands(exeCommands, root) for (line in result.successLines) { Log.i(TAG, "echo success line: $line") } for (line in result.errorLines) { Log.i(TAG, "echo error line: $line") } return result } fun sendCommands(commands: ArrayList, root: Boolean = false): CmdResult { val result = CmdResult(-1, "", "") var status = -1 if (commands.isEmpty()) { return result } Log.i(TAG, "exe commands : $commands") var proc: Process? = null var successBufReader: BufferedReader? = null var errorBufReader: BufferedReader? = null var dos: DataOutputStream? = null try { proc = if (root) Runtime.getRuntime().exec(ROOT_SHELL) else Runtime.getRuntime().exec(SHELL) dos = DataOutputStream(proc!!.outputStream) for (command in commands) { if (command.isEmpty()) { continue } dos.writeBytes(command) dos.writeBytes(LINE_BREAK) dos.flush() } dos.writeBytes(EXIT + LINE_BREAK) dos.flush() status = proc.waitFor() successBufReader = BufferedReader(InputStreamReader(proc.inputStream)) errorBufReader = BufferedReader(InputStreamReader(proc.errorStream)) var lineStr: String? = null do { lineStr = successBufReader.readLine() if (lineStr.isNullOrEmpty()) break lineStr = trimLine(lineStr) if (lineStr !in commands) result.successLines.add(lineStr) Log.i(TAG, " success line echo : $lineStr") } while (true) do { lineStr = errorBufReader.readLine() if (lineStr.isNullOrEmpty()) break lineStr = trimLine(lineStr) if (lineStr !in commands) result.errorLines.add(lineStr) Log.i(TAG, " error line echo : $lineStr") } while (true) } catch (e: IOException) { e.printStackTrace() } catch (e: Exception) { e.printStackTrace() } finally { try { dos?.close() successBufReader?.close() errorBufReader?.close() } catch (e: IOException) { e.printStackTrace() } proc?.destroy() } Log.i(TAG, "error message:${result.errorLines} and status $status") if (result.errorLines.size > 0 && result.successLines.size <= 0) status = -1 result.status = status return result } private fun trimLine(line: String): String { var res = line if ('$' in line) res = line.split('$')[1].trimStart() if ('#' in line) res = line.split('$')[1].trimStart() res = res.replace("\r", "").replace("\n", "") return res } fun screenShot(storePath: String) { // Runtime.getRuntime().exec("screencap -p /sdcard/screen.png") exeCmdEcho("screencap -p $storePath", true) } fun sendKey(keyCode: String) { val cmdKey = "input keyevent $keyCode" exeCmdEcho(cmdKey, true) } fun sendMultiKey(keyPath: String) { val keyEvents = ArrayList() val keys = keyPath.split(Constants.SLASH) for (stepKey in keys) { var delay = "1" if (Constants.VERTICAL_BAR in stepKey) { val params = stepKey.split(Constants.VERTICAL_BAR) delay = params[1] } if (Constants.ASTERISK in stepKey) { val params = stepKey.split(Constants.ASTERISK) for (i in 0..params[1].toInt()) { val keyEvent = EmulateKey() keyEvent.key = params[0] keyEvent.delay = delay keyEvents.add(keyEvent) } } else { val keyEvent = EmulateKey() keyEvent.key = stepKey keyEvent.delay = delay keyEvents.add(keyEvent) } } val commands = ArrayList() for (keyEvent in keyEvents) { Log.i(TAG, "send key: $keyEvent") val cmdKey = "input keyevent ${Constants.KEY_MAP[keyEvent.key]}" commands.add(cmdKey) commands.add("sleep ${keyEvent.delay}") } exeCmdEcho(commands, true) } fun tcpCapture(tcpdump: String): Process? { val captureCmd = "tcpdump -p -vv -s 0 -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'" // >> /sdcard/capture.txt\n" val proc = getRootShell() var dos: DataOutputStream? = null try { dos = DataOutputStream(proc!!.outputStream) dos.write(captureCmd.toByteArray()) dos.flush() val result = proc.waitFor() Log.i(TAG, "result: $result") } catch (e: Exception) { e.printStackTrace() } finally { dos?.close() } object : Thread() { override fun run() { val insBr = BufferedReader(InputStreamReader(proc?.inputStream)) try { var lineStr: String? = null do { lineStr = insBr.readLine() if (lineStr.isNullOrEmpty()) break lineStr = trimLine(lineStr) Log.i(TAG, " tcpdump echo line : $lineStr") } while (true) } catch (e: IOException) { e.printStackTrace() } finally { try { proc?.inputStream?.close() } catch (e: IOException) { e.printStackTrace() } } } }.start() object : Thread() { override fun run() { val errBr = BufferedReader(InputStreamReader(proc?.errorStream)) try { var errLine: String? = null do { errLine = errBr.readLine() if (errLine.isNullOrEmpty()) break errLine = trimLine(errLine) Log.i(TAG, " tcpdump error line : $errLine") } while (true) } catch (e: IOException) { e.printStackTrace() } finally { try { proc?.errorStream?.close() } catch (e: IOException) { e.printStackTrace() } } } }.start() return proc } fun killTcpdump() { val result = exeCmdEcho("killall", true) if (result.status != -1) exeCmdEcho("killall tcpdump", true) else { val psResult = exeCmdEcho("ps | grep tcpdump", true) for (line in psResult.successLines) { val arr = line.split(' ') val items = ArrayList() arr.forEach { if (!it.isNullOrEmpty()) items.add(it) } if (items.isNotEmpty()) { exeCmdEcho("kill " + items[1], true) } } } } fun resetApp(packageName: String) { exeCmdEcho("pm clear $packageName", true) } fun launchApp(launchInfo: String) { exeCmdEcho("am start -n $launchInfo", true) } fun stopApp(packageName: String) { exeCmdEcho("am force-stop $packageName", true) } class CmdResult { var status: Int = 0 var successLines = ArrayList() var errorLines = ArrayList() constructor(status: Int) { this.status = status } constructor(result: Int, successMsg: String, errorMsg: String) { this.status = result if (!successMsg.isNullOrEmpty()) this.successLines.add(successMsg) if (!errorMsg.isNullOrEmpty()) this.errorLines.add(errorMsg) } } }