Skip to content

Commit fe9f806

Browse files
committed
1 parent a362006 commit fe9f806

File tree

11 files changed

+101
-31
lines changed

11 files changed

+101
-31
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@ android {
2828
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
2929
}
3030
}
31+
buildFeatures.buildConfig = true
3132
}
3233

3334
dependencies {
3435
implementation(project(":lib"))
35-
implementation("androidx.activity:activity:1.7.2")
36+
implementation("androidx.activity:activity:1.8.0")
3637
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
3738
testImplementation("junit:junit:4.13.2")
3839
androidTestImplementation("androidx.test:runner:1.5.2")

app/src/main/java/be/mygod/librootkotlinx/demo/App.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package be.mygod.librootkotlinx.demo
22

33
import android.app.Application
44
import android.util.Log
5+
import be.mygod.librootkotlinx.AppProcess
6+
import be.mygod.librootkotlinx.Logger
57
import be.mygod.librootkotlinx.RootServer
68
import be.mygod.librootkotlinx.RootSession
79
import kotlinx.coroutines.DelicateCoroutinesApi
@@ -19,7 +21,14 @@ class App : Application() {
1921
// simply initialize a global instance, this is a very lightweight operation
2022
rootManager = object : RootSession() {
2123
override val timeout get() = TimeUnit.SECONDS.toMillis(5)
22-
override suspend fun initServer(server: RootServer) = server.init(this@App)
24+
override suspend fun initServer(server: RootServer) {
25+
if (BuildConfig.DEBUG) Logger.me = object : Logger {
26+
override fun d(m: String?, t: Throwable?) {
27+
Log.d("RootServer", m, t)
28+
}
29+
}
30+
server.init(this@App, AppProcess.shouldRelocateHeuristics)
31+
}
2332
}
2433
Log.d("App", "init")
2534
}

app/src/main/java/be/mygod/librootkotlinx/demo/MainActivity.kt

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,35 @@
11
package be.mygod.librootkotlinx.demo
22

33
import android.os.Bundle
4+
import android.os.Process
5+
import android.text.method.ScrollingMovementMethod
46
import android.widget.TextView
57
import androidx.activity.ComponentActivity
68
import androidx.lifecycle.lifecycleScope
7-
import be.mygod.librootkotlinx.ParcelableInt
89
import be.mygod.librootkotlinx.ParcelableString
910
import be.mygod.librootkotlinx.RootCommand
1011
import be.mygod.librootkotlinx.RootCommandChannel
1112
import kotlinx.coroutines.CoroutineScope
13+
import kotlinx.coroutines.Dispatchers
1214
import kotlinx.coroutines.channels.produce
1315
import kotlinx.coroutines.channels.toList
1416
import kotlinx.coroutines.launch
17+
import kotlinx.coroutines.withContext
1518
import kotlinx.parcelize.Parcelize
1619

1720
class MainActivity : ComponentActivity() {
1821
@Parcelize
19-
class GetRoot : RootCommand<ParcelableInt> {
20-
override suspend fun execute() = ParcelableInt(android.os.Process.myUid())
22+
class SimpleTest : RootCommand<ParcelableString> {
23+
override suspend fun execute() = ParcelableString("uid: ${Process.myUid()}\n" + withContext(Dispatchers.IO) {
24+
// try to execute a restricted subprocess command
25+
val process = ProcessBuilder("/system/bin/iptables", "-L", "INPUT").start()
26+
var output = process.inputStream.reader().readText()
27+
when (val exit = process.waitFor()) {
28+
0 -> { }
29+
else -> output += "Process exited with $exit".toByteArray()
30+
}
31+
output
32+
})
2133
}
2234

2335
@Parcelize
@@ -31,13 +43,14 @@ class MainActivity : ComponentActivity() {
3143
override fun onCreate(savedInstanceState: Bundle?) {
3244
super.onCreate(savedInstanceState)
3345
setContentView(R.layout.activity_main)
46+
val text = findViewById<TextView>(android.R.id.text1)
47+
text.movementMethod = ScrollingMovementMethod()
3448
lifecycleScope.launch {
35-
findViewById<TextView>(android.R.id.text1).text = try {
36-
val result = App.rootManager.use {
37-
it.execute(GetRoot()).value.toString() + "\n" +
38-
it.create(ChannelDemo(), lifecycleScope).toList().joinToString { it.value }
49+
text.text = try {
50+
App.rootManager.use {
51+
it.execute(SimpleTest()).value + '\n' + it.create(ChannelDemo(), lifecycleScope).toList()
52+
.joinToString { it.value }
3953
}
40-
"Got result from root: $result"
4154
} catch (e: Exception) {
4255
e.printStackTrace()
4356
e.stackTraceToString()

app/src/main/res/layout/activity_main.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
android:layout_height="match_parent"
66
android:padding="16dp"
77
android:id="@android:id/text1"
8-
tools:context=".MainActivity">
9-
</TextView>
8+
android:scrollbars="vertical"
9+
tools:context=".MainActivity" />

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
plugins {
2-
val androidGradleVersion = "8.1.1"
2+
val androidGradleVersion = "8.1.2"
33
id("com.android.application") version androidGradleVersion apply false
44
id("com.android.library") version androidGradleVersion apply false
5-
id("com.github.ben-manes.versions") version "0.47.0"
5+
id("com.github.ben-manes.versions") version "0.49.0"
66
id("org.jetbrains.kotlin.android") version "1.9.10" apply false
77
}
88

gradle/wrapper/gradle-wrapper.jar

346 Bytes
Binary file not shown.

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

gradlew

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ done
8383
# This is normally unused
8484
# shellcheck disable=SC2034
8585
APP_BASE_NAME=${0##*/}
86-
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
86+
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87+
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
8788

8889
# Use the maximum available, or set MAX_FD != -1 to use that value.
8990
MAX_FD=maximum

lib/consumer-rules.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-if public class be.mygod.librootkotlinx.RootServer {
2-
private void doInit(android.content.Context, boolean, java.lang.String);
2+
private void doInit(android.content.Context, boolean, java.lang.String, java.lang.String);
33
}
44
-keep class be.mygod.librootkotlinx.RootServer {
55
public static void main(java.lang.String[]);

lib/src/main/java/be/mygod/librootkotlinx/AppProcess.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package be.mygod.librootkotlinx
33
import android.content.Context
44
import android.os.Build
55
import android.os.Debug
6+
import android.system.Os
67
import androidx.annotation.RequiresApi
78
import java.io.File
89
import java.io.IOException
@@ -63,21 +64,20 @@ object AppProcess {
6364
throw IllegalArgumentException("No valid linker section found")
6465
}
6566

66-
val myExe get() = try {
67+
val myExe get() = "/proc/${Os.getpid()}/exe"
68+
val myExeCanonical get() = try {
6769
File("/proc/self/exe").canonicalPath.also { require(!it.startsWith("/proc/")) { it } }
6870
} catch (e: Exception) {
69-
Logger.me.i("warning: couldn't resolve self exe", e)
71+
Logger.me.d("warning: couldn't resolve self exe", e)
7072
"/system/bin/app_process"
7173
}
72-
@Deprecated("myExe is now always canonical", ReplaceWith("myExe"))
73-
val myExeCanonical get() = myExe
7474

7575
/**
7676
* Try to guess whether enabling relocation would work best.
7777
* It seems some Android 5-7 devices give random permission denials without relocation.
7878
* See also VPNHotspot#173.
7979
*/
80-
val shouldRelocateHeuristics get() = Build.VERSION.SDK_INT < 26 || myExe.startsWith("/data/")
80+
val shouldRelocateHeuristics get() = Build.VERSION.SDK_INT < 26 || myExeCanonical.startsWith("/data/")
8181

8282
/**
8383
* To workaround Samsung's stupid kernel patch that prevents exec, we need to relocate exe outside of /data.
@@ -98,7 +98,7 @@ object AppProcess {
9898
val ldConfig = "$apexPath/etc/ld.config.txt"
9999
val masterLdConfig = genericLdConfigFilePath
100100
val section = try {
101-
File(masterLdConfig).useLines { findLinkerSection(it, myExe) }
101+
File(masterLdConfig).useLines { findLinkerSection(it, myExeCanonical) }
102102
} catch (e: Exception) {
103103
Logger.me.w("Failed to locate system section", e)
104104
"system"

0 commit comments

Comments
 (0)