mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-03-28 02:02:16 +00:00
Add module tests
This commit is contained in:
parent
6c05f2ae85
commit
f5f9b285c0
@ -14,7 +14,7 @@ object Const {
|
||||
else Build.SUPPORTED_32_BIT_ABIS.firstOrNull()
|
||||
|
||||
// Paths
|
||||
const val MAGISK_PATH = "/data/adb/modules"
|
||||
const val MODULE_PATH = "/data/adb/modules"
|
||||
const val TMPDIR = "/dev/tmp"
|
||||
const val MAGISK_LOG = "/cache/magisk.log"
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.nio.ExtendedFile
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
@ -12,7 +13,7 @@ import java.io.IOException
|
||||
import java.util.Locale
|
||||
|
||||
data class LocalModule(
|
||||
private val path: String,
|
||||
private val base: ExtendedFile,
|
||||
) : Module() {
|
||||
private val svc get() = ServiceLocator.networkService
|
||||
|
||||
@ -24,20 +25,18 @@ data class LocalModule(
|
||||
var description: String = ""
|
||||
var updateInfo: OnlineModule? = null
|
||||
var outdated = false
|
||||
|
||||
private var updateUrl: String = ""
|
||||
private val removeFile = RootUtils.fs.getFile(path, "remove")
|
||||
private val disableFile = RootUtils.fs.getFile(path, "disable")
|
||||
private val updateFile = RootUtils.fs.getFile(path, "update")
|
||||
private val riruFolder = RootUtils.fs.getFile(path, "riru")
|
||||
private val zygiskFolder = RootUtils.fs.getFile(path, "zygisk")
|
||||
private val unloaded = RootUtils.fs.getFile(zygiskFolder, "unloaded")
|
||||
|
||||
val updated: Boolean get() = updateFile.exists()
|
||||
val isRiru: Boolean get() = (id == "riru-core") || riruFolder.exists()
|
||||
val isZygisk: Boolean get() = zygiskFolder.exists()
|
||||
val zygiskUnloaded: Boolean get() = unloaded.exists()
|
||||
val hasAction: Boolean;
|
||||
private val removeFile = base.getChildFile("remove")
|
||||
private val disableFile = base.getChildFile("disable")
|
||||
private val updateFile = base.getChildFile("update")
|
||||
val zygiskFolder = base.getChildFile("zygisk")
|
||||
|
||||
val updated get() = updateFile.exists()
|
||||
val isRiru = (id == "riru-core") || base.getChildFile("riru").exists()
|
||||
val isZygisk = zygiskFolder.exists()
|
||||
val zygiskUnloaded = zygiskFolder.getChildFile("unloaded").exists()
|
||||
val hasAction = base.getChildFile("action.sh").exists()
|
||||
|
||||
var enable: Boolean
|
||||
get() = !disableFile.exists()
|
||||
@ -90,19 +89,16 @@ data class LocalModule(
|
||||
|
||||
init {
|
||||
runCatching {
|
||||
parseProps(Shell.cmd("dos2unix < $path/module.prop").exec().out)
|
||||
parseProps(Shell.cmd("dos2unix < $base/module.prop").exec().out)
|
||||
}
|
||||
|
||||
if (id.isEmpty()) {
|
||||
val sep = path.lastIndexOf('/')
|
||||
id = path.substring(sep + 1)
|
||||
id = base.name
|
||||
}
|
||||
|
||||
if (name.isEmpty()) {
|
||||
name = id
|
||||
}
|
||||
|
||||
hasAction = RootUtils.fs.getFile(path, "action.sh").exists()
|
||||
}
|
||||
|
||||
suspend fun fetch(): Boolean {
|
||||
@ -125,14 +121,14 @@ data class LocalModule(
|
||||
|
||||
companion object {
|
||||
|
||||
fun loaded() = RootUtils.fs.getFile(Const.MAGISK_PATH).exists()
|
||||
fun loaded() = RootUtils.fs.getFile(Const.MODULE_PATH).exists()
|
||||
|
||||
suspend fun installed() = withContext(Dispatchers.IO) {
|
||||
RootUtils.fs.getFile(Const.MAGISK_PATH)
|
||||
RootUtils.fs.getFile(Const.MODULE_PATH)
|
||||
.listFiles()
|
||||
.orEmpty()
|
||||
.filter { !it.isFile && !it.isHidden }
|
||||
.map { LocalModule("${Const.MAGISK_PATH}/${it.name}") }
|
||||
.map { LocalModule(it) }
|
||||
.sortedBy { it.name.lowercase(Locale.ROOT) }
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,17 @@ import androidx.annotation.Keep
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -21,6 +29,17 @@ class AdditionalTest : BaseTest {
|
||||
private const val SHELL_PKG = "com.android.shell"
|
||||
private const val LSPOSED_CATEGORY = "org.lsposed.manager.LAUNCH_MANAGER"
|
||||
private const val LSPOSED_PKG = "org.lsposed.manager"
|
||||
|
||||
private lateinit var modules: List<LocalModule>
|
||||
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun before() {
|
||||
BaseTest.prerequisite()
|
||||
runBlocking {
|
||||
modules = LocalModule.installed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
@ -29,9 +48,23 @@ class AdditionalTest : BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLaunchLsposedManager() {
|
||||
fun testModuleCount() {
|
||||
var expected = 2
|
||||
if (Environment.lsposed()) expected++
|
||||
if (Environment.shamiko()) expected++
|
||||
assertEquals("Module count incorrect", expected, modules.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLsposed() {
|
||||
assumeTrue(Environment.lsposed())
|
||||
|
||||
val module = modules.find { it.id == "zygisk_lsposed" }
|
||||
assertNotNull("zygisk_lsposed is not installed", module)
|
||||
module!!
|
||||
assertFalse("zygisk_lsposed is not enabled", module.zygiskUnloaded)
|
||||
|
||||
// Launch lsposed manager to ensure the module is active
|
||||
uiAutomation.executeShellCommand(
|
||||
"am start -c $LSPOSED_CATEGORY $SHELL_PKG/.BugreportWarningActivity"
|
||||
).let { pfd -> AutoCloseInputStream(pfd).use { it.readBytes() } }
|
||||
@ -42,4 +75,33 @@ class AdditionalTest : BaseTest {
|
||||
device.wait(Until.hasObject(By.res(pattern)), TimeUnit.SECONDS.toMillis(10))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModule01() {
|
||||
val module = modules.find { it.id == "test_01" }
|
||||
assertNotNull("test_01 is not installed", module)
|
||||
assertTrue(
|
||||
"/system/etc/newfile should exist",
|
||||
RootUtils.fs.getFile("/system/etc/newfile").exists()
|
||||
)
|
||||
assertFalse(
|
||||
"/system/bin/screenrecord should not exist",
|
||||
RootUtils.fs.getFile("/system/bin/screenrecord").exists()
|
||||
)
|
||||
module!!
|
||||
assertTrue("test_01 should be zygisk unloaded", module.zygiskUnloaded)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModule02() {
|
||||
val module = modules.find { it.id == "test_02" }
|
||||
assertNotNull("test_02 is not installed", module)
|
||||
module!!
|
||||
assertTrue("test_02 should be zygisk unloaded", module.zygiskUnloaded)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModule03() {
|
||||
assertNull("test_03 should be removed", modules.find { it.id == "test_03" })
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,18 @@ import androidx.annotation.Keep
|
||||
import androidx.core.net.toUri
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
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.module.LocalModule
|
||||
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 com.topjohnwu.superuser.nio.ExtendedFile
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
@ -37,7 +42,7 @@ class Environment : BaseTest {
|
||||
return Build.VERSION.SDK_INT >= 27 && Build.VERSION.SDK_INT <= 34
|
||||
}
|
||||
|
||||
private fun shamiko(): Boolean {
|
||||
fun shamiko(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= 27
|
||||
}
|
||||
|
||||
@ -72,6 +77,55 @@ class Environment : BaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupModule01(root: ExtendedFile) {
|
||||
val error = "test_01 setup failed"
|
||||
val path = root.getChildFile("test_01")
|
||||
|
||||
// Create /system/etc/newfile
|
||||
val etc = path.getChildFile("system").getChildFile("etc")
|
||||
assertTrue(error, etc.mkdirs())
|
||||
assertTrue(error, etc.getChildFile("newfile").createNewFile())
|
||||
|
||||
// Delete /system/bin/screenrecord
|
||||
val bin = path.getChildFile("system").getChildFile("bin")
|
||||
assertTrue(error, bin.mkdirs())
|
||||
assertTrue(error, Shell.cmd("mknod $bin/screenrecord c 0 0").exec().isSuccess)
|
||||
|
||||
// Create an empty zygisk folder
|
||||
val module = LocalModule(path)
|
||||
assertTrue(error, module.zygiskFolder.mkdir())
|
||||
|
||||
assertTrue(error, Shell.cmd("set_default_perm $path").exec().isSuccess)
|
||||
}
|
||||
|
||||
private fun setupModule02(root: ExtendedFile) {
|
||||
val error = "test_02 setup failed"
|
||||
val path = root.getChildFile("test_02")
|
||||
|
||||
// Create invalid zygisk libraries
|
||||
val module = LocalModule(path)
|
||||
assertTrue(error, module.zygiskFolder.mkdirs())
|
||||
assertTrue(error, module.zygiskFolder.getChildFile("armeabi-v7a.so").createNewFile())
|
||||
assertTrue(error, module.zygiskFolder.getChildFile("arm64-v8a.so").createNewFile())
|
||||
assertTrue(error, module.zygiskFolder.getChildFile("x86.so").createNewFile())
|
||||
assertTrue(error, module.zygiskFolder.getChildFile("x86_64.so").createNewFile())
|
||||
|
||||
assertTrue(error, Shell.cmd("set_default_perm $path").exec().isSuccess)
|
||||
}
|
||||
|
||||
private fun setupModule03(root: ExtendedFile) {
|
||||
val error = "test_03 setup failed"
|
||||
val path = root.getChildFile("test_03")
|
||||
|
||||
// Create a new module but mark is as "remove"
|
||||
val module = LocalModule(path)
|
||||
assertTrue(error, path.mkdirs())
|
||||
assertTrue(error, path.getChildFile("service.sh").createNewFile())
|
||||
module.remove = true
|
||||
|
||||
assertTrue(error, Shell.cmd("set_default_perm $path").exec().isSuccess)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setupEnvironment() {
|
||||
runBlocking {
|
||||
@ -114,6 +168,11 @@ class Environment : BaseTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val root = RootUtils.fs.getFile(Const.MODULE_PATH)
|
||||
setupModule01(root)
|
||||
setupModule02(root)
|
||||
setupModule03(root)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -621,6 +621,15 @@ is_legacy_script() {
|
||||
return $?
|
||||
}
|
||||
|
||||
# $1 = MODPATH
|
||||
set_default_perm() {
|
||||
set_perm_recursive $1 0 0 0755 0644
|
||||
set_perm_recursive $1/system/bin 0 2000 0755 0755
|
||||
set_perm_recursive $1/system/xbin 0 2000 0755 0755
|
||||
set_perm_recursive $1/system/system_ext/bin 0 2000 0755 0755
|
||||
set_perm_recursive $1/system/vendor/bin 0 2000 0755 0755 u:object_r:vendor_file:s0
|
||||
}
|
||||
|
||||
# Require OUTFD, ZIPFILE to be set
|
||||
install_module() {
|
||||
rm -rf $TMPDIR
|
||||
@ -683,13 +692,7 @@ install_module() {
|
||||
if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
|
||||
ui_print "- Extracting module files"
|
||||
unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
|
||||
|
||||
# Default permissions
|
||||
set_perm_recursive $MODPATH 0 0 0755 0644
|
||||
set_perm_recursive $MODPATH/system/bin 0 2000 0755 0755
|
||||
set_perm_recursive $MODPATH/system/xbin 0 2000 0755 0755
|
||||
set_perm_recursive $MODPATH/system/system_ext/bin 0 2000 0755 0755
|
||||
set_perm_recursive $MODPATH/system/vendor/bin 0 2000 0755 0755 u:object_r:vendor_file:s0
|
||||
set_default_perm $MODPATH
|
||||
fi
|
||||
|
||||
# Load customization script
|
||||
|
Loading…
x
Reference in New Issue
Block a user