Remove dependency on librootjava
This commit is contained in:
@@ -93,7 +93,6 @@ dependencies {
|
|||||||
implementation("com.jakewharton.timber:timber:4.7.1")
|
implementation("com.jakewharton.timber:timber:4.7.1")
|
||||||
implementation("com.linkedin.dexmaker:dexmaker:2.28.0")
|
implementation("com.linkedin.dexmaker:dexmaker:2.28.0")
|
||||||
implementation("com.takisoft.preferencex:preferencex-simplemenu:1.1.0")
|
implementation("com.takisoft.preferencex:preferencex-simplemenu:1.1.0")
|
||||||
implementation("eu.chainfire:librootjava:1.3.0")
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.2")
|
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.2")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8")
|
||||||
testImplementation("junit:junit:4.13")
|
testImplementation("junit:junit:4.13")
|
||||||
|
|||||||
72
mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt
Normal file
72
mobile/src/main/java/be/mygod/librootkotlinx/AppProcess.kt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package be.mygod.librootkotlinx
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Debug
|
||||||
|
import android.os.Process
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object AppProcess {
|
||||||
|
/**
|
||||||
|
* Based on: https://android.googlesource.com/platform/bionic/+/aff9a34/linker/linker.cpp#3397
|
||||||
|
*/
|
||||||
|
@get:RequiresApi(29)
|
||||||
|
val genericLdConfigFilePath: String get() {
|
||||||
|
"/system/etc/ld.config.${Build.VERSION.SDK_INT}.txt".let { if (File(it).isFile) return it }
|
||||||
|
if (Build.VERSION.SDK_INT >= 30) "/linkerconfig/ld.config.txt".let {
|
||||||
|
check(File(it).isFile) { "failed to find generated linker configuration from \"$it\"" }
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
val prop = Class.forName("android.os.SystemProperties")
|
||||||
|
if (prop.getDeclaredMethod("getBoolean", String::class.java, Boolean::class.java).invoke(null,
|
||||||
|
"ro.vndk.lite", false) as Boolean) return "/system/etc/ld.config.vndk_lite.txt"
|
||||||
|
when (val version = prop.getDeclaredMethod("get", String::class.java, String::class.java).invoke(null,
|
||||||
|
"ro.vndk.version", "") as String) {
|
||||||
|
"", "current" -> { }
|
||||||
|
else -> "/system/etc/ld.config.$version.txt".let { if (File(it).isFile) return it }
|
||||||
|
}
|
||||||
|
return "/system/etc/ld.config.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
val myExe get() = "/proc/${Process.myPid()}/exe"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To workaround Samsung's stupid kernel patch that prevents exec, we need to relocate exe outside of /data.
|
||||||
|
* See also: https://github.com/Chainfire/librootjava/issues/19
|
||||||
|
*
|
||||||
|
* @return The script to be executed to perform relocation and the relocated binary path.
|
||||||
|
*/
|
||||||
|
fun relocateScript(token: String): Pair<StringBuilder, String> {
|
||||||
|
val script = StringBuilder()
|
||||||
|
val (baseDir, relocated) = if (Build.VERSION.SDK_INT < 29) "/dev" to "/dev/app_process_$token" else {
|
||||||
|
val apexPath = "/apex/$token"
|
||||||
|
script.appendln("[ -d $apexPath ] || " +
|
||||||
|
"mkdir $apexPath && " +
|
||||||
|
// we need to mount a new tmpfs to override noexec flag
|
||||||
|
"mount -t tmpfs -o size=1M tmpfs $apexPath || exit 1")
|
||||||
|
// unfortunately native ld.config.txt only recognizes /data,/system,/system_ext as system directories;
|
||||||
|
// to link correctly, we need to add our path to the linker config too
|
||||||
|
val ldConfig = "$apexPath/etc/ld.config.txt"
|
||||||
|
script.appendln("[ -f $ldConfig ] || " +
|
||||||
|
"mkdir -p $apexPath/etc && " +
|
||||||
|
"echo dir.system = $apexPath >$ldConfig && " +
|
||||||
|
"cat $genericLdConfigFilePath >>$ldConfig || exit 1")
|
||||||
|
"$apexPath/bin" to "$apexPath/bin/app_process"
|
||||||
|
}
|
||||||
|
script.appendln("[ -f $relocated ] || " +
|
||||||
|
"mkdir -p $baseDir && " +
|
||||||
|
"cp $myExe $relocated && " +
|
||||||
|
"chmod 700 $relocated || exit 1")
|
||||||
|
return script to relocated
|
||||||
|
}
|
||||||
|
|
||||||
|
fun launchString(packageCodePath: String, clazz: String, appProcess: String, niceName: String?): String {
|
||||||
|
val debugParams = if (Debug.isDebuggerConnected()) when (Build.VERSION.SDK_INT) {
|
||||||
|
in 29..Int.MAX_VALUE -> "-XjdwpProvider:adbconnection"
|
||||||
|
28 -> "-XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable"
|
||||||
|
else -> "-Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable"
|
||||||
|
} else ""
|
||||||
|
val extraParams = if (niceName != null) " --nice-name=$niceName" else ""
|
||||||
|
return "CLASSPATH=$packageCodePath exec $appProcess $debugParams /system/bin$extraParams $clazz"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package be.mygod.librootkotlinx
|
package be.mygod.librootkotlinx
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
@@ -11,9 +10,6 @@ import android.util.Log
|
|||||||
import androidx.collection.LongSparseArray
|
import androidx.collection.LongSparseArray
|
||||||
import androidx.collection.set
|
import androidx.collection.set
|
||||||
import androidx.collection.valueIterator
|
import androidx.collection.valueIterator
|
||||||
import eu.chainfire.librootjava.AppProcess
|
|
||||||
import eu.chainfire.librootjava.Logger
|
|
||||||
import eu.chainfire.librootjava.RootJava
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
@@ -161,35 +157,10 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
val uuid = context.packageName + '@' + if (persistence.canRead()) persistence.readText() else {
|
val uuid = context.packageName + '@' + if (persistence.canRead()) persistence.readText() else {
|
||||||
UUID.randomUUID().toString().also { persistence.writeText(it) }
|
UUID.randomUUID().toString().also { persistence.writeText(it) }
|
||||||
}
|
}
|
||||||
// to workaround Samsung's stupid kernel patch, we need to relocate outside of /data: https://github.com/Chainfire/librootjava/issues/19
|
val (script, relocated) = AppProcess.relocateScript(uuid)
|
||||||
val (baseDir, relocated) = if (Build.VERSION.SDK_INT < 29) "/dev" to "/dev/app_process_$uuid" else {
|
script.appendln(AppProcess.launchString(context.packageCodePath, RootServer::class.java.name, relocated,
|
||||||
val apexPath = "/apex/$uuid"
|
niceName) + " $token2")
|
||||||
writer.writeBytes("[ -d $apexPath ] || " +
|
writer.writeBytes(script.toString())
|
||||||
"mkdir $apexPath && " +
|
|
||||||
// we need to mount a new tmpfs to override noexec flag
|
|
||||||
"mount -t tmpfs -o size=1M tmpfs $apexPath || exit 1\n")
|
|
||||||
// unfortunately native ld.config.txt only recognizes /data,/system,/system_ext as system directories;
|
|
||||||
// to link correctly, we need to add our path to the linker config too
|
|
||||||
val ldConfig = "$apexPath/etc/ld.config.txt"
|
|
||||||
writer.writeBytes("[ -f $ldConfig ] || " +
|
|
||||||
"mkdir -p $apexPath/etc && " +
|
|
||||||
"echo dir.system = $apexPath >$ldConfig && " +
|
|
||||||
"cat $genericLdConfigFilePath >>$ldConfig || exit 1\n")
|
|
||||||
"$apexPath/bin" to "$apexPath/bin/app_process"
|
|
||||||
}
|
|
||||||
writer.writeBytes("[ -f $relocated ] || " +
|
|
||||||
"mkdir -p $baseDir && " +
|
|
||||||
"cp /proc/${android.os.Process.myPid()}/exe $relocated && " +
|
|
||||||
"chmod 700 $relocated || exit 1\n")
|
|
||||||
writer.writeBytes(RootJava.getLaunchString(
|
|
||||||
context.packageCodePath + " exec", // hack: plugging in exec
|
|
||||||
RootServer::class.java.name, relocated,
|
|
||||||
AppProcess.guessIfAppProcessIs64Bits(File("/proc/self/exe").canonicalPath),
|
|
||||||
arrayOf("$token2\n"), niceName).let { result ->
|
|
||||||
if (Build.VERSION.SDK_INT < 24) result
|
|
||||||
// undo the patch on newer APIs to let linker do the work
|
|
||||||
else result.replaceFirst(" LD_LIBRARY_PATH=", " __SUPPRESSED_LD_LIBRARY_PATH=")
|
|
||||||
})
|
|
||||||
writer.flush()
|
writer.flush()
|
||||||
reader.lookForToken(token2) // wait for ready signal
|
reader.lookForToken(token2) // wait for ready signal
|
||||||
output = writer
|
output = writer
|
||||||
@@ -365,10 +336,6 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
var isDebugEnabled = false
|
var isDebugEnabled = false
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
Logger.setDebugLogging(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val TAG = "RootServer"
|
private const val TAG = "RootServer"
|
||||||
private const val SUCCESS = 0
|
private const val SUCCESS = 0
|
||||||
@@ -435,7 +402,6 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
|
|
||||||
private fun rootMain(args: Array<String>) {
|
private fun rootMain(args: Array<String>) {
|
||||||
require(args.isNotEmpty())
|
require(args.isNotEmpty())
|
||||||
if (Build.VERSION.SDK_INT < 24) RootJava.restoreOriginalLdLibraryPath()
|
|
||||||
val mainInitialized = CountDownLatch(1)
|
val mainInitialized = CountDownLatch(1)
|
||||||
val main = Thread({
|
val main = Thread({
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
|||||||
@@ -4,37 +4,13 @@ package be.mygod.librootkotlinx
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.*
|
import android.util.*
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class NoShellException(cause: Throwable) : Exception("Root missing", cause)
|
class NoShellException(cause: Throwable) : Exception("Root missing", cause)
|
||||||
|
|
||||||
/**
|
|
||||||
* Based on: https://android.googlesource.com/platform/bionic/+/aff9a34/linker/linker.cpp#3397
|
|
||||||
*/
|
|
||||||
@get:RequiresApi(29)
|
|
||||||
val genericLdConfigFilePath: String get() {
|
|
||||||
"/system/etc/ld.config.${Build.VERSION.SDK_INT}.txt".let { if (File(it).isFile) return it }
|
|
||||||
if (Build.VERSION.SDK_INT >= 30) "/linkerconfig/ld.config.txt".let {
|
|
||||||
check(File(it).isFile) { "failed to find generated linker configuration from \"$it\"" }
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
val prop = Class.forName("android.os.SystemProperties")
|
|
||||||
if (prop.getDeclaredMethod("getBoolean", String::class.java, Boolean::class.java).invoke(null,
|
|
||||||
"ro.vndk.lite", false) as Boolean) return "/system/etc/ld.config.vndk_lite.txt"
|
|
||||||
when (val version = prop.getDeclaredMethod("get", String::class.java, String::class.java).invoke(null,
|
|
||||||
"ro.vndk.version", "") as String) {
|
|
||||||
"", "current" -> { }
|
|
||||||
else -> "/system/etc/ld.config.$version.txt".let { if (File(it).isFile) return it }
|
|
||||||
}
|
|
||||||
return "/system/etc/ld.config.txt"
|
|
||||||
}
|
|
||||||
|
|
||||||
val systemContext by lazy {
|
val systemContext by lazy {
|
||||||
val classActivityThread = Class.forName("android.app.ActivityThread")
|
val classActivityThread = Class.forName("android.app.ActivityThread")
|
||||||
val activityThread = classActivityThread.getMethod("systemMain").invoke(null)
|
val activityThread = classActivityThread.getMethod("systemMain").invoke(null)
|
||||||
|
|||||||
Reference in New Issue
Block a user