Add support for daemon launching without relocation

Improves RAM usage and potentially addresses #368.

Inspired by: fc42e8274e/service/src/main/java/com/topjohnwu/superuser/internal/RootServiceManager.java (L186)
This commit is contained in:
Mygod
2022-05-15 18:15:23 -04:00
parent b411ecc8c9
commit 8ad03e38e8
2 changed files with 32 additions and 14 deletions

View File

@@ -22,7 +22,7 @@
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-if public class be.mygod.librootkotlinx.RootServer { -if public class be.mygod.librootkotlinx.RootServer {
private void doInit(android.content.Context, java.lang.String); private void doInit(android.content.Context, java.lang.String, boolean);
} }
-keep class be.mygod.librootkotlinx.RootServer { -keep class be.mygod.librootkotlinx.RootServer {
public static void main(java.lang.String[]); public static void main(java.lang.String[]);

View File

@@ -86,6 +86,7 @@ class RootServer {
} }
} }
class LaunchException(cause: Throwable) : RuntimeException("Failed to launch root daemon", cause)
class UnexpectedExitException : RemoteException("Root process exited unexpectedly") class UnexpectedExitException : RemoteException("Root process exited unexpectedly")
private lateinit var process: Process private lateinit var process: Process
@@ -130,7 +131,7 @@ class RootServer {
Logger.me.w(line) Logger.me.w(line)
} }
} }
private fun doInit(context: Context, niceName: String) { private fun doInit(context: Context, niceName: String, shouldRelocate: Boolean = false) {
try { try {
val (reader, writer) = try { val (reader, writer) = try {
process = ProcessBuilder("su").start() process = ProcessBuilder("su").start()
@@ -147,6 +148,7 @@ class RootServer {
} }
try { try {
val token2 = UUID.randomUUID().toString() val token2 = UUID.randomUUID().toString()
writer.writeBytes(if (shouldRelocate) {
val persistence = File(context.codeCacheDir, ".librootkotlinx-uuid") val persistence = File(context.codeCacheDir, ".librootkotlinx-uuid")
val uuid = context.packageName + '@' + try { val uuid = context.packageName + '@' + try {
persistence.readText() persistence.readText()
@@ -156,11 +158,15 @@ class RootServer {
val (script, relocated) = AppProcess.relocateScript(uuid) val (script, relocated) = AppProcess.relocateScript(uuid)
script.appendLine(AppProcess.launchString(context.packageCodePath, RootServer::class.java.name, script.appendLine(AppProcess.launchString(context.packageCodePath, RootServer::class.java.name,
relocated, niceName) + " $token2") relocated, niceName) + " $token2")
writer.writeBytes(script.toString()) script.toString()
} else {
AppProcess.launchString(context.packageCodePath, RootServer::class.java.name, AppProcess.myExe,
niceName) + " $token2\n"
})
writer.flush() writer.flush()
reader.lookForToken(token2) // wait for ready signal reader.lookForToken(token2) // wait for ready signal
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException("Failed to launch root daemon", e) throw LaunchException(e)
} }
output = writer output = writer
require(!active) require(!active)
@@ -204,7 +210,19 @@ class RootServer {
* @param niceName Name to call the rooted Java process. * @param niceName Name to call the rooted Java process.
*/ */
suspend fun init(context: Context, niceName: String = "${context.packageName}:root") { suspend fun init(context: Context, niceName: String = "${context.packageName}:root") {
withContext(Dispatchers.IO) { doInit(context, niceName) } withContext(Dispatchers.IO) {
try {
doInit(context, niceName)
} catch (e: LaunchException) {
try {
doInit(context, niceName, true)
} catch (e2: LaunchException) {
e2.addSuppressed(e)
throw e2
}
Logger.me.w("Root without relocation has failed", RuntimeException(e))
}
}
callbackListenerExit = GlobalScope.async(Dispatchers.IO) { callbackListenerExit = GlobalScope.async(Dispatchers.IO) {
val errorReader = async(Dispatchers.IO) { val errorReader = async(Dispatchers.IO) {
try { try {