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) { val exeCommands = ArrayList() exeCommands.add(cmd) exeCmdEcho(exeCommands, root) } fun exeCmdEcho(commands: ArrayList, root: Boolean = false): List? { Log.i(TAG, "exe cmd echo: $commands") val exeCommands = ArrayList() exeCommands.addAll(commands) val results = sendCommands(exeCommands, root) for (line in results!!) { Log.i(TAG, "echo line: $line") } return results } fun sendCommands(commands: ArrayList, root: Boolean = false): List? { val results = ArrayList() var status = -1 if (commands.isEmpty()) { return null } Log.i(TAG, "exe commands : $commands") var proc: Process? = null var successBufReader: BufferedReader? = null var errorBufReader: BufferedReader? = null var errorMsg: StringBuilder? = 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() errorMsg = StringBuilder() 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) results.add(lineStr) Log.i(TAG, " success line echo : $lineStr") } while (true) results.add("----------") do { lineStr = errorBufReader.readLine() if (lineStr.isNullOrEmpty()) break lineStr = trimLine(lineStr) if (lineStr !in commands) results.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:$errorMsg and status $status") return results } 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() { exeCmdEcho("killall", true) // exeCmdEcho("killall tcpdump", 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) } }