Test su request via instrumentation

This commit is contained in:
topjohnwu 2024-12-24 23:11:53 -08:00 committed by John Wu
parent 2baedf74d1
commit 08ea937f7c
3 changed files with 80 additions and 37 deletions

View File

@ -8,16 +8,16 @@ import androidx.core.net.toUri
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.download.DownloadNotifier
import com.topjohnwu.magisk.core.download.DownloadProcessor
import com.topjohnwu.magisk.core.ktx.cachedFile
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.tasks.AppMigration
import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertTrue
import org.junit.Assume.assumeTrue
@ -34,7 +34,11 @@ class Environment {
companion object {
@BeforeClass
@JvmStatic
fun before() = MagiskAppTest.before()
fun before() {
assertTrue("Should have root access", Shell.getShell().isRoot)
// Make sure the root service is running
RootUtils.Connection.await()
}
fun lsposed(): Boolean {
return Build.VERSION.SDK_INT >= 27 && Build.VERSION.SDK_INT <= 34
@ -88,23 +92,6 @@ class Environment {
}
}
@Test
fun setupShellGrantTest() {
runBlocking {
// Inject an undetermined + mute logging policy for ADB shell
val policy = SuPolicy(
uid = 2000,
logging = false,
notification = false,
until = 0L
)
ServiceLocator.policyDB.update(policy)
// Bypass the need to actually show a dialog
Config.suAutoResponse = Config.Value.SU_AUTO_ALLOW
Config.prefs.edit().commit()
}
}
@Test
fun setupAppHide() {
runBlocking {

View File

@ -1,14 +1,26 @@
package com.topjohnwu.magisk.test
import android.app.Instrumentation
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import androidx.annotation.Keep
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.superuser.Shell
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.model.su.SuPolicy
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import java.io.FileInputStream
import java.util.concurrent.TimeUnit
@Keep
@RunWith(AndroidJUnit4::class)
@ -17,15 +29,69 @@ class MagiskAppTest {
companion object {
@BeforeClass
@JvmStatic
fun before() {
assertTrue("Should have root access", Shell.getShell().isRoot)
// Make sure the root service is running
RootUtils.Connection.await()
fun before() = Environment.before()
}
private lateinit var inst: Instrumentation
private val uiAutomation get() = inst.uiAutomation
@Before
fun setup() {
inst = InstrumentationRegistry.getInstrumentation()
}
@Test
fun testZygisk() {
assertTrue("Zygisk should be enabled", Info.isZygiskEnabled)
}
@Test
fun testSuRequest() {
// Bypass the need to actually show a dialog
Config.suAutoResponse = Config.Value.SU_AUTO_ALLOW
Config.prefs.edit().commit()
// Inject an undetermined + mute logging policy for ADB shell
val policy = SuPolicy(
uid = 2000,
logging = false,
notification = false,
until = 0L
)
runBlocking {
ServiceLocator.policyDB.update(policy)
}
val filter = IntentFilter(Intent.ACTION_VIEW)
filter.addCategory(Intent.CATEGORY_DEFAULT)
val monitor = inst.addMonitor(filter, null, false)
// Try to call su from ADB shell
val cmd = if (Build.VERSION.SDK_INT < 24) {
// API 23 runs executeShellCommand as root
"/system/xbin/su 2000 su -c id"
} else {
"su -c id"
}
val pfd = uiAutomation.executeShellCommand(cmd)
// Make sure SuRequestActivity is launched
val suRequest = monitor.waitForActivityWithTimeout(TimeUnit.SECONDS.toMillis(10))
assertNotNull("SuRequestActivity is not launched", suRequest)
// Check that the request went through
FileInputStream(pfd.fileDescriptor).use {
assertTrue(
"Cannot grant root permission from shell",
it.reader().readText().contains("uid=0")
)
}
// Check that the database is updated
runBlocking {
val policy = ServiceLocator.policyDB.fetch(2000)
?: throw AssertionError("PolicyDB is invalid")
assertEquals("Policy for shell is incorrect", SuPolicy.ALLOW, policy.policy)
}
}
}

View File

@ -67,11 +67,6 @@ run_tests() {
# Run app tests
am_instrument '.MagiskAppTest,.AdditionalTest'
# Test shell su request
am_instrument '.Environment#setupShellGrantTest'
adb shell /system/xbin/su 2000 su -c id | tee /dev/fd/2 | grep -q 'uid=0'
adb shell am force-stop com.topjohnwu.magisk
# Test app hiding
am_instrument '.Environment#setupAppHide'
wait_for_pm com.topjohnwu.magisk
@ -79,11 +74,6 @@ run_tests() {
# Make sure it still works
am_instrument '.MagiskAppTest' true
# Test shell su request
am_instrument '.Environment#setupShellGrantTest' true
adb shell /system/xbin/su 2000 su -c id | tee /dev/fd/2 | grep -q 'uid=0'
adb shell am force-stop repackaged.com.topjohnwu.magisk
# Test app restore
am_instrument '.Environment#setupAppRestore' true
wait_for_pm repackaged.com.topjohnwu.magisk