Improve performance
This commit is contained in:
@@ -77,7 +77,6 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var process: Process
|
private lateinit var process: Process
|
||||||
private lateinit var worker: Thread
|
|
||||||
/**
|
/**
|
||||||
* Thread safety: needs to be protected by mutex.
|
* Thread safety: needs to be protected by mutex.
|
||||||
*/
|
*/
|
||||||
@@ -86,7 +85,7 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
@Volatile
|
@Volatile
|
||||||
var active = false
|
var active = false
|
||||||
private var counter = 0L
|
private var counter = 0L
|
||||||
private val callbackListenerExit = CompletableDeferred<Unit>()
|
private lateinit var callbackListenerExit: Deferred<Unit>
|
||||||
private val callbackLookup = LongSparseArray<Callback>()
|
private val callbackLookup = LongSparseArray<Callback>()
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
@@ -120,31 +119,33 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
warnLogger(line)
|
warnLogger(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private suspend fun doInit(context: Context, niceName: String) = coroutineScope {
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
private suspend fun doInit(context: Context, niceName: String) {
|
||||||
val init = async {
|
|
||||||
try {
|
|
||||||
process = ProcessBuilder("su").start()
|
|
||||||
val token1 = UUID.randomUUID().toString()
|
|
||||||
val writer = DataOutputStream(process.outputStream.buffered())
|
|
||||||
writer.writeBytes("echo $token1\n")
|
|
||||||
writer.flush()
|
|
||||||
val reader = process.inputStream.bufferedReader()
|
|
||||||
reader.lookForToken(token1)
|
|
||||||
if (DEBUG) Log.d(TAG, "Root shell initialized")
|
|
||||||
reader to writer
|
|
||||||
} catch (e: Exception) {
|
|
||||||
throw NoShellException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val token2 = UUID.randomUUID().toString()
|
val token2 = UUID.randomUUID().toString()
|
||||||
val launchString = async(Dispatchers.IO) {
|
val list = coroutineScope {
|
||||||
val appProcess = AppProcess.getAppProcess()
|
val init = async(start = CoroutineStart.LAZY) {
|
||||||
RootJava.getLaunchString(context.packageCodePath + " exec", // hack: plugging in exec
|
try {
|
||||||
RootServer::class.java.name, appProcess, AppProcess.guessIfAppProcessIs64Bits(appProcess),
|
process = ProcessBuilder("su").start()
|
||||||
arrayOf("$token2\n"), niceName)
|
val token1 = UUID.randomUUID().toString()
|
||||||
|
val writer = DataOutputStream(process.outputStream.buffered())
|
||||||
|
writer.writeBytes("echo $token1\n")
|
||||||
|
writer.flush()
|
||||||
|
val reader = process.inputStream.bufferedReader()
|
||||||
|
reader.lookForToken(token1)
|
||||||
|
if (DEBUG) Log.d(TAG, "Root shell initialized")
|
||||||
|
reader to writer
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw NoShellException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val launchString = async(start = CoroutineStart.LAZY) {
|
||||||
|
val appProcess = AppProcess.getAppProcess()
|
||||||
|
RootJava.getLaunchString(context.packageCodePath + " exec", // hack: plugging in exec
|
||||||
|
RootServer::class.java.name, appProcess, AppProcess.guessIfAppProcessIs64Bits(appProcess),
|
||||||
|
arrayOf("$token2\n"), niceName)
|
||||||
|
}
|
||||||
|
awaitAll(init, launchString)
|
||||||
}
|
}
|
||||||
val list = awaitAll(init, launchString)
|
|
||||||
val (reader, writer) = list[0] as Pair<BufferedReader, DataOutputStream>
|
val (reader, writer) = list[0] as Pair<BufferedReader, DataOutputStream>
|
||||||
writer.writeBytes(list[1] as String)
|
writer.writeBytes(list[1] as String)
|
||||||
writer.flush()
|
writer.flush()
|
||||||
@@ -180,29 +181,23 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
*/
|
*/
|
||||||
suspend fun init(context: Context, niceName: String = "${context.packageName}:root") {
|
suspend fun init(context: Context, niceName: String = "${context.packageName}:root") {
|
||||||
val future = CompletableDeferred<Unit>()
|
val future = CompletableDeferred<Unit>()
|
||||||
worker = Thread {
|
callbackListenerExit = GlobalScope.async(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
runBlocking { doInit(context, niceName) }
|
doInit(context, niceName)
|
||||||
future.complete(Unit)
|
future.complete(Unit)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
future.completeExceptionally(e)
|
future.completeExceptionally(e)
|
||||||
callbackListenerExit.complete(Unit)
|
return@async
|
||||||
return@Thread
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
callbackSpin()
|
callbackSpin()
|
||||||
} catch (e: Throwable) {
|
|
||||||
callbackListenerExit.completeExceptionally(e)
|
|
||||||
return@Thread
|
|
||||||
} finally {
|
} finally {
|
||||||
if (DEBUG) Log.d(TAG, "Waiting for exit")
|
if (DEBUG) Log.d(TAG, "Waiting for exit")
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
runBlocking { closeInternal(true) }
|
closeInternal(true)
|
||||||
}
|
}
|
||||||
check(process.errorStream.available() == 0) // stderr should not be used
|
check(process.errorStream.available() == 0) // stderr should not be used
|
||||||
callbackListenerExit.complete(Unit)
|
|
||||||
}
|
}
|
||||||
worker.start()
|
|
||||||
future.await()
|
future.await()
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ object RootManager : RootSession() {
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
class RootInit : RootCommandNoResult {
|
class RootInit : RootCommandNoResult {
|
||||||
override suspend fun execute(): Parcelable? {
|
override suspend fun execute(): Parcelable? {
|
||||||
|
RootServer.DEBUG = BuildConfig.DEBUG
|
||||||
Services.init(RootJava.getSystemContext())
|
Services.init(RootJava.getSystemContext())
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user