| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package com.example.modifier.utils
- import android.util.Log
- import com.example.modifier.model.AdbResult
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.coroutineScope
- import kotlinx.coroutines.delay
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
- class ADB {
- companion object {
- const val TAG = "ADB"
- val adbPath by lazy { "${getContext().applicationInfo.nativeLibraryDir}/libadb.so" }
- private val homeDir by lazy { getContext().filesDir }
- private val cacheDir by lazy { getContext().cacheDir }
- suspend fun connect(): Boolean {
- return run ls@{
- repeat(1000) {
- adb("connect", "localhost:5555")
- delay(5000)
- adb("devices")
- if (adb("shell", "echo", "hello").exitCode == 0) {
- return@ls true
- }
- delay(3000)
- }
- return@ls false
- }
- }
- /**
- * Send a raw ADB command
- */
- suspend fun adb(vararg command: String): AdbResult {
- runCatching {
- val fullCommand = command.toMutableList().also {
- it.add(0, adbPath)
- if (command.firstOrNull() == "shell") {
- it.add(1, "-s")
- it.add(2, "localhost:5555")
- }
- }
- Log.i(TAG, "ADB command: ${fullCommand.joinToString(" ")}".replace(adbPath, "adb"))
- var output = ""
- var error = ""
- val process = withContext(Dispatchers.IO) {
- createProcess(*fullCommand.toTypedArray())
- }
- coroutineScope {
- launch {
- process.inputStream.bufferedReader().useLines { line ->
- line.forEach {
- output += it + "\n"
- Log.i(TAG, "ADB out: $it")
- }
- }
- }
- launch {
- process.errorStream.bufferedReader().useLines { line ->
- line.forEach {
- error += it + "\n"
- Log.e(TAG, "ADB err: $it")
- }
- }
- }
- }
- withContext(Dispatchers.IO) {
- process.waitFor()
- }
- return AdbResult(exitCode = process.exitValue())
- }.onFailure {
- Log.wtf(TAG, "Error running ADB command: ${it.message}", it)
- }
- return AdbResult()
- }
- /**
- * Send a raw ADB command
- */
- suspend fun adbShell(vararg commands: String): AdbResult {
- Log.i(TAG, "ADB command: ${commands.joinToString("\n")}")
- runCatching {
- var output = ""
- var error = ""
- val process = withContext(Dispatchers.IO) {
- createProcess(adbPath, "-s", "localhost:5555", "shell")
- }
- process.outputStream.bufferedWriter().use { writer ->
- commands.forEach { command ->
- writer.write(command)
- writer.newLine()
- writer.flush()
- }
- }
- coroutineScope {
- launch {
- process.inputStream.bufferedReader().useLines { line ->
- line.forEach {
- output += it + "\n"
- Log.i(TAG, "ADB out: $it")
- }
- }
- }
- launch {
- process.errorStream.bufferedReader().useLines { line ->
- line.forEach {
- error += it + "\n"
- Log.e(TAG, "ADB err: $it")
- }
- }
- }
- }
- withContext(Dispatchers.IO) {
- process.waitFor()
- }
- Log.i(TAG, "ADB exit code: ${process.exitValue()}")
- return AdbResult(output = output, error = error, exitCode = process.exitValue())
- }.onFailure {
- Log.wtf(TAG, "Error running ADB command: ${it.message}", it)
- }
- return AdbResult()
- }
- fun createProcess(vararg command: String): Process {
- return ProcessBuilder(*command)
- .directory(homeDir)
- .apply {
- // redirectErrorStream(true)
- environment().apply {
- put("HOME", homeDir.path)
- put("TMPDIR", cacheDir.path)
- }
- }.start()
- }
- }
- }
|