mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 12:05:30 +00:00
Fix stub app loading on older Android versions
This commit is contained in:
parent
a3381da7ed
commit
9016e6727d
@ -9,10 +9,8 @@ import dalvik.system.BaseDexClassLoader;
|
||||
|
||||
public class DynamicClassLoader extends BaseDexClassLoader {
|
||||
|
||||
private static final ClassLoader base = Object.class.getClassLoader();
|
||||
|
||||
public DynamicClassLoader(File apk) {
|
||||
this(apk, base);
|
||||
this(apk, getSystemClassLoader());
|
||||
}
|
||||
|
||||
public DynamicClassLoader(File apk, ClassLoader parent) {
|
||||
@ -29,7 +27,7 @@ public class DynamicClassLoader extends BaseDexClassLoader {
|
||||
|
||||
try {
|
||||
// Then check boot classpath
|
||||
return base.loadClass(name);
|
||||
return getSystemClassLoader().loadClass(name);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
try {
|
||||
// Next try current dex
|
||||
@ -47,7 +45,7 @@ public class DynamicClassLoader extends BaseDexClassLoader {
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
URL resource = base.getResource(name);
|
||||
URL resource = getSystemClassLoader().getResource(name);
|
||||
if (resource != null)
|
||||
return resource;
|
||||
resource = findResource(name);
|
||||
@ -59,7 +57,7 @@ public class DynamicClassLoader extends BaseDexClassLoader {
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
return new CompoundEnumeration<>(base.getResources(name),
|
||||
return new CompoundEnumeration<>(getSystemClassLoader().getResources(name),
|
||||
findResources(name), getParent().getResources(name));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ package com.topjohnwu.magisk.core
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.content.res.AssetManager
|
||||
import android.content.res.Configuration
|
||||
@ -13,16 +14,12 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.utils.syncLocale
|
||||
import com.topjohnwu.magisk.ktx.unwrap
|
||||
|
||||
lateinit var AppApkPath: String
|
||||
|
||||
fun Resources.addAssetPath(path: String) = StubApk.addAssetPath(this, path)
|
||||
|
||||
fun Context.patch(): Context {
|
||||
resources.patch()
|
||||
return this
|
||||
}
|
||||
|
||||
fun Resources.patch(): Resources {
|
||||
if (isRunningAsStub)
|
||||
addAssetPath(AppApkPath)
|
||||
@ -30,6 +27,21 @@ fun Resources.patch(): Resources {
|
||||
return this
|
||||
}
|
||||
|
||||
fun Context.patch(): Context {
|
||||
unwrap().resources.patch()
|
||||
return this
|
||||
}
|
||||
|
||||
// Wrapping is only necessary for ContextThemeWrapper to support configuration overrides
|
||||
fun Context.wrap(): Context {
|
||||
patch()
|
||||
return object : ContextWrapper(this) {
|
||||
override fun createConfigurationContext(config: Configuration): Context {
|
||||
return super.createConfigurationContext(config).wrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createNewResources(): Resources {
|
||||
val asset = AssetManager::class.java.newInstance()
|
||||
val config = Configuration(AppContext.resources.configuration)
|
||||
|
@ -5,7 +5,6 @@ import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -18,9 +17,9 @@ import androidx.annotation.WorkerThread
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.patch
|
||||
import com.topjohnwu.magisk.core.utils.RequestInstall
|
||||
import com.topjohnwu.magisk.core.utils.UninstallPackage
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import com.topjohnwu.magisk.ktx.reflectField
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import java.util.concurrent.CountDownLatch
|
||||
@ -56,11 +55,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base.patch())
|
||||
}
|
||||
|
||||
override fun createConfigurationContext(config: Configuration): Context {
|
||||
return super.createConfigurationContext(config).patch()
|
||||
super.attachBaseContext(base.wrap())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -12,12 +12,12 @@ import org.gradle.api.tasks.Sync
|
||||
import org.gradle.kotlin.dsl.filter
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import java.io.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import java.util.zip.Deflater
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipOutputStream
|
||||
import java.util.zip.*
|
||||
|
||||
private fun Project.androidBase(configure: Action<BaseExtension>) =
|
||||
extensions.configure("android", configure)
|
||||
@ -219,22 +219,23 @@ fun Project.setupStub() {
|
||||
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
|
||||
}
|
||||
|
||||
val buffer = ByteArrayOutputStream(apk.length().toInt())
|
||||
val newApk = ZipOutputStream(FileOutputStream(apk))
|
||||
ZipFile(apkTmp).use {
|
||||
newApk.use { new ->
|
||||
new.setLevel(Deflater.BEST_COMPRESSION)
|
||||
new.putNextEntry(ZipEntry("AndroidManifest.xml"))
|
||||
it.getInputStream(it.getEntry("AndroidManifest.xml")).transferTo(new)
|
||||
new.closeEntry()
|
||||
new.finish()
|
||||
val buffer = ByteArrayOutputStream()
|
||||
apkTmp.inputStream().use {
|
||||
object : GZIPOutputStream(buffer) {
|
||||
init {
|
||||
def.setLevel(Deflater.BEST_COMPRESSION)
|
||||
}
|
||||
ZipOutputStream(buffer).use { arsc ->
|
||||
arsc.setLevel(Deflater.BEST_COMPRESSION)
|
||||
arsc.putNextEntry(ZipEntry("resources.arsc"))
|
||||
it.getInputStream(it.getEntry("resources.arsc")).transferTo(arsc)
|
||||
arsc.closeEntry()
|
||||
arsc.finish()
|
||||
}.use { o ->
|
||||
it.transferTo(o)
|
||||
}
|
||||
}
|
||||
ZipFile(apkTmp).use { o ->
|
||||
ZipOutputStream(apk.outputStream()).use { n ->
|
||||
n.setLevel(Deflater.BEST_COMPRESSION)
|
||||
n.putNextEntry(ZipEntry("AndroidManifest.xml"))
|
||||
o.getInputStream(o.getEntry("AndroidManifest.xml")).transferTo(n)
|
||||
n.closeEntry()
|
||||
n.finish()
|
||||
}
|
||||
}
|
||||
apkTmp.delete()
|
||||
|
@ -131,7 +131,7 @@ class StubClassLoader extends ClassLoader {
|
||||
class DelegateClassLoader extends ClassLoader {
|
||||
|
||||
DelegateClassLoader() {
|
||||
super(null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,6 +34,7 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
@ -95,6 +96,12 @@ public class DownloadActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
Runtime.getRuntime().exit(0);
|
||||
}
|
||||
|
||||
private void error(Throwable e) {
|
||||
Log.e(getClass().getSimpleName(), "", e);
|
||||
finish();
|
||||
@ -154,7 +161,8 @@ public class DownloadActivity extends Activity {
|
||||
SecretKey key = new SecretKeySpec(Bytes.key(), "AES");
|
||||
IvParameterSpec iv = new IvParameterSpec(Bytes.iv());
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, iv);
|
||||
var is = new CipherInputStream(new ByteArrayInputStream(Bytes.res()), cipher);
|
||||
var is = new GZIPInputStream(new CipherInputStream(
|
||||
new ByteArrayInputStream(Bytes.res()), cipher));
|
||||
try (is; out) {
|
||||
APKInstall.transfer(is, out);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user