Use built-in DelegateLastClassLoader for extensions (#3874)
Assisted-by: Claude:claude-opus-5
This commit is contained in:
@@ -13,13 +13,13 @@ import eu.kanade.tachiyomi.source.Source
|
|||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.util.lang.Hash
|
import eu.kanade.tachiyomi.util.lang.Hash
|
||||||
import eu.kanade.tachiyomi.util.storage.copyAndSetReadOnlyTo
|
import eu.kanade.tachiyomi.util.storage.copyAndSetReadOnlyTo
|
||||||
import eu.kanade.tachiyomi.util.system.ChildFirstPathClassLoader
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import mihon.app.di.appGraph
|
import mihon.app.di.appGraph
|
||||||
|
import mihon.data.dalvik.DelegateLastClassLoaderCompat
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ internal object ExtensionLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val classLoader = try {
|
val classLoader = try {
|
||||||
ChildFirstPathClassLoader(appInfo.sourceDir, null, context.classLoader)
|
DelegateLastClassLoaderCompat(appInfo.sourceDir, null, context.classLoader)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($pkgName)" }
|
logcat(LogPriority.ERROR, e) { "Extension load error: $extName ($pkgName)" }
|
||||||
return LoadResult.Error
|
return LoadResult.Error
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.util.system
|
|
||||||
|
|
||||||
import dalvik.system.PathClassLoader
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.net.URL
|
|
||||||
import java.util.Enumeration
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A parent-last class loader that will try in order:
|
|
||||||
* - the system class loader
|
|
||||||
* - the child class loader
|
|
||||||
* - the parent class loader.
|
|
||||||
*/
|
|
||||||
class ChildFirstPathClassLoader(
|
|
||||||
dexPath: String,
|
|
||||||
librarySearchPath: String?,
|
|
||||||
parent: ClassLoader,
|
|
||||||
) : PathClassLoader(dexPath, librarySearchPath, parent) {
|
|
||||||
|
|
||||||
private val systemClassLoader: ClassLoader? = getSystemClassLoader()
|
|
||||||
|
|
||||||
override fun loadClass(name: String?, resolve: Boolean): Class<*> {
|
|
||||||
var c = findLoadedClass(name)
|
|
||||||
|
|
||||||
if (c == null && systemClassLoader != null) {
|
|
||||||
try {
|
|
||||||
c = systemClassLoader.loadClass(name)
|
|
||||||
} catch (_: ClassNotFoundException) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == null) {
|
|
||||||
c = try {
|
|
||||||
findClass(name)
|
|
||||||
} catch (_: ClassNotFoundException) {
|
|
||||||
super.loadClass(name, resolve)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolve) {
|
|
||||||
resolveClass(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getResource(name: String?): URL? {
|
|
||||||
return systemClassLoader?.getResource(name)
|
|
||||||
?: findResource(name)
|
|
||||||
?: super.getResource(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getResources(name: String?): Enumeration<URL> {
|
|
||||||
val systemUrls = systemClassLoader?.getResources(name)
|
|
||||||
val localUrls = findResources(name)
|
|
||||||
val parentUrls = parent?.getResources(name)
|
|
||||||
val urls = buildList {
|
|
||||||
while (systemUrls?.hasMoreElements() == true) {
|
|
||||||
add(systemUrls.nextElement())
|
|
||||||
}
|
|
||||||
|
|
||||||
while (localUrls?.hasMoreElements() == true) {
|
|
||||||
add(localUrls.nextElement())
|
|
||||||
}
|
|
||||||
|
|
||||||
while (parentUrls?.hasMoreElements() == true) {
|
|
||||||
add(parentUrls.nextElement())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return object : Enumeration<URL> {
|
|
||||||
val iterator = urls.iterator()
|
|
||||||
|
|
||||||
override fun hasMoreElements() = iterator.hasNext()
|
|
||||||
override fun nextElement() = iterator.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getResourceAsStream(name: String?): InputStream? {
|
|
||||||
return try {
|
|
||||||
getResource(name)?.openStream()
|
|
||||||
} catch (_: IOException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package mihon.data.dalvik
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import dalvik.system.DelegateLastClassLoader
|
||||||
|
import dalvik.system.PathClassLoader
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.Enumeration
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
|
fun DelegateLastClassLoaderCompat(
|
||||||
|
dexPath: String,
|
||||||
|
librarySearchPath: String?,
|
||||||
|
parent: ClassLoader,
|
||||||
|
): ClassLoader {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||||
|
DelegateLastClassLoader(dexPath, librarySearchPath, parent)
|
||||||
|
} else {
|
||||||
|
DelegateLastPathClassLoader(dexPath, librarySearchPath, parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backport of [DelegateLastClassLoader], which was added in API 27.
|
||||||
|
*/
|
||||||
|
private class DelegateLastPathClassLoader(
|
||||||
|
dexPath: String,
|
||||||
|
librarySearchPath: String?,
|
||||||
|
parent: ClassLoader,
|
||||||
|
) : PathClassLoader(dexPath, librarySearchPath, parent) {
|
||||||
|
|
||||||
|
private val bootClassLoader: ClassLoader? = Any::class.java.classLoader
|
||||||
|
|
||||||
|
override fun loadClass(name: String?, resolve: Boolean): Class<*> {
|
||||||
|
findLoadedClass(name)?.let { return it }
|
||||||
|
|
||||||
|
if (bootClassLoader != null) {
|
||||||
|
try {
|
||||||
|
return bootClassLoader.loadClass(name)
|
||||||
|
} catch (_: ClassNotFoundException) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromSuper = try {
|
||||||
|
return findClass(name)
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
e
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
parent.loadClass(name)
|
||||||
|
} catch (_: ClassNotFoundException) {
|
||||||
|
throw fromSuper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getResource(name: String?): URL? {
|
||||||
|
return bootClassLoader?.getResource(name)
|
||||||
|
?: findResource(name)
|
||||||
|
?: parent?.getResource(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getResources(name: String?): Enumeration<URL> {
|
||||||
|
val resources = buildList {
|
||||||
|
bootClassLoader?.getResources(name)?.let { addAll(it.toList()) }
|
||||||
|
findResources(name)?.let { addAll(it.toList()) }
|
||||||
|
parent?.getResources(name)?.let { addAll(it.toList()) }
|
||||||
|
}
|
||||||
|
return Collections.enumeration(resources)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user