package com.duolebo.blyrobot.util import android.text.TextUtils 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" private var rootShell = "su" // 通过id判断是否有root权限,部分盒子是没有su的 fun checkRootPermission(): Boolean { var proc = getShellProc(ROOT_SHELL) ?: return false Log.i(TAG, "get root proc success!") val commands = ArrayList() commands.add("id -u") val result = this.sendCommands(commands, proc) Log.i(TAG, "check permission error ${result.errorLines} and message ${result.successLines}") if (isRoot(result)) { return true } else { proc = getShellProc(SHELL) ?: return false commands.clear() commands.add("id -u") val result = this.sendCommands(commands, proc) if (isRoot(result)) return true } return false } private fun isRoot(result: CmdResult): Boolean { if (result.status != -1) { for (line in result.successLines) { if (line.contains("(root)") || line == "0") { rootShell = ROOT_SHELL return true } } } return false } fun getShellProc(shell: String): Process? { var proc: Process? = null try { proc = Runtime.getRuntime().exec(shell) } catch (e: Exception) { e.printStackTrace() } if (proc == null) { Log.i(TAG, "get root proc failed") } return proc } fun getRootShellString(): String { return rootShell } fun exeCmdSync(cmd: String): Process? { Log.i(TAG, "exe cmd: $cmd") var proc: Process? = null try { proc = Runtime.getRuntime().exec(getRootShellString()) } 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 proc = if (root) Runtime.getRuntime().exec(getRootShellString()) else Runtime.getRuntime().exec(SHELL) val result = sendCommands(exeCommands, proc) 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, proc: Process): CmdResult { val result = CmdResult(-1, "", "") var status = -1 if (commands.isEmpty()) { return result } Log.i(TAG, "exe commands : $commands") var successBufReader: BufferedReader? = null var errorBufReader: BufferedReader? = null var dos: DataOutputStream? = null try { 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) // proc?.destroy() } catch (e: IOException) { e.printStackTrace() } catch (e: Exception) { e.printStackTrace() } finally { try { dos?.close() successBufReader?.close() errorBufReader?.close() } catch (e: IOException) { e.printStackTrace() } } 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" var key = stepKey if (Constants.VERTICAL_BAR in stepKey) { val params = stepKey.split(Constants.VERTICAL_BAR) key = params[0] delay = params[1] } if (Constants.ASTERISK in stepKey) { val params = stepKey.split(Constants.ASTERISK) if (params.size > 1 && TextUtils.isDigitsOnly(params[1])) { for (i in 0..params[1].toInt()) { val keyEvent = EmulateKey() keyEvent.key = params[0] keyEvent.delay = delay keyEvents.add(keyEvent) } } else { Log.i(TAG, "multi key event is invalid.") } } else { val keyEvent = EmulateKey() keyEvent.key = key 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) if (keyEvent.delay.toInt() > 0) commands.add("sleep ${keyEvent.delay}") } exeCmdEcho(commands, true) } fun tcpCapture(path: String): Process? { val captureCmd = "tcpdump -p -vv -s 0 -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420' >> $path" val proc = getShellProc(ROOT_SHELL) var dos: DataOutputStream? = null try { dos = DataOutputStream(proc!!.outputStream) dos.write(captureCmd.toByteArray()) dos.writeBytes(LINE_BREAK) 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() { try { 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) } } } } catch (e: Exception) { e.printStackTrace() } } fun isAppActive(packageName: String): Boolean { val result = exeCmdEcho("dumpsys activity | grep mFocusedActivity", true) if (result.status == 0) { for (line in result.successLines) { if (line.contains(packageName)) return true } } return false } fun resetApp(packageName: String) { exeCmdEcho("pm clear $packageName", true) } fun launchApp(launchInfo: String) { exeCmdEcho("am start -n $launchInfo", true) } fun stopApp(packageName: String) { try { exeCmdEcho("am force-stop $packageName", true) } catch (e:Exception) { e.printStackTrace() } } 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) } } }