Introduce DynamicClassLoader

This commit is contained in:
topjohnwu 2019-08-04 23:49:09 -07:00
parent 41134466ed
commit 010e4de4e1
3 changed files with 65 additions and 5 deletions

View File

@ -9,10 +9,10 @@ import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.PatchAPK import com.topjohnwu.magisk.utils.PatchAPK
import com.topjohnwu.magisk.utils.RootUtils import com.topjohnwu.magisk.utils.RootUtils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import dalvik.system.DexClassLoader
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -27,7 +27,7 @@ private fun RemoteFileService.patchPackage(apk: File, id: Int): File {
val patched = File(apk.parent, "patched.apk") val patched = File(apk.parent, "patched.apk")
try { try {
// Try using the new APK to patch itself // Try using the new APK to patch itself
val loader = DexClassLoader(apk.path, apk.parent, null, ClassLoader.getSystemClassLoader()) val loader = DynamicClassLoader(apk)
loader.loadClass("a.a") loader.loadClass("a.a")
.getMethod("patchAPK", String::class.java, String::class.java, String::class.java) .getMethod("patchAPK", String::class.java, String::class.java, String::class.java)
.invoke(null, apk.path, patched.path, packageName) .invoke(null, apk.path, patched.path, packageName)

View File

@ -18,10 +18,10 @@ import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.ui.base.MagiskActivity import com.topjohnwu.magisk.ui.base.MagiskActivity
import com.topjohnwu.magisk.ui.base.MagiskFragment import com.topjohnwu.magisk.ui.base.MagiskFragment
import com.topjohnwu.magisk.utils.ISafetyNetHelper import com.topjohnwu.magisk.utils.ISafetyNetHelper
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.view.MarkDownWindow import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.magisk.view.dialogs.* import com.topjohnwu.magisk.view.dialogs.*
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import dalvik.system.DexClassLoader
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import java.io.File import java.io.File
@ -97,8 +97,7 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
private fun updateSafetyNet(dieOnError: Boolean) { private fun updateSafetyNet(dieOnError: Boolean) {
try { try {
val loader = DexClassLoader(EXT_APK.path, EXT_APK.parent, null, val loader = DynamicClassLoader(EXT_APK)
ISafetyNetHelper::class.java.classLoader)
val clazz = loader.loadClass("com.topjohnwu.snet.Snet") val clazz = loader.loadClass("com.topjohnwu.snet.Snet")
val helper = clazz.getMethod("newHelper", val helper = clazz.getMethod("newHelper",
Class::class.java, String::class.java, Activity::class.java, Any::class.java) Class::class.java, String::class.java, Activity::class.java, Any::class.java)

View File

@ -0,0 +1,61 @@
package com.topjohnwu.magisk.utils
import dalvik.system.DexClassLoader
import java.io.File
import java.io.IOException
import java.net.URL
import java.util.*
@Suppress("FunctionName")
inline fun <reified T> T.DynamicClassLoader(apk: File) = DynamicClassLoader(apk, T::class.java.classLoader)
class DynamicClassLoader(apk: File, parent: ClassLoader?)
: DexClassLoader(apk.path, apk.parent, null, parent) {
private val base by lazy { Any::class.java.classLoader!! }
@Throws(ClassNotFoundException::class)
override fun loadClass(name: String, resolve: Boolean) : Class<*>
= findLoadedClass(name) ?: runCatching {
base.loadClass(name)
}.getOrElse {
runCatching {
findClass(name)
}.getOrElse { err ->
runCatching {
parent.loadClass(name)
}.getOrElse { throw err }
}
}
override fun getResource(name: String) = base.getResource(name)
?: findResource(name)
?: parent?.getResource(name)
@Throws(IOException::class)
override fun getResources(name: String): Enumeration<URL> {
val resources = mutableListOf(
base.getResources(name),
findResources(name), parent.getResources(name))
return object : Enumeration<URL> {
override fun hasMoreElements(): Boolean {
while (true) {
if (resources.isEmpty())
return false
if (!resources[0].hasMoreElements()) {
resources.removeAt(0)
} else {
return true
}
}
}
override fun nextElement(): URL {
if (!hasMoreElements())
throw NoSuchElementException()
return resources[0].nextElement()
}
}
}
}