diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index cd7fc9cc9..2640304f6 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -31,6 +31,10 @@ # Stub -keep class com.topjohnwu.magisk.core.App { (java.lang.Object); } +-keepclassmembers class androidx.appcompat.app.AppCompatDelegateImpl { + boolean mActivityHandlesUiModeChecked; + boolean mActivityHandlesUiMode; +} # Strip Timber verbose and debug logging -assumenosideeffects class timber.log.Timber$Tree { diff --git a/app/src/main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt b/app/src/main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt index af62f8fab..ed79c7aa4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.res.Configuration import android.os.Build +import android.os.Bundle import android.widget.Toast import androidx.annotation.CallSuper import androidx.appcompat.app.AppCompatActivity @@ -16,6 +17,7 @@ import androidx.core.content.ContextCompat import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.core.wrap +import com.topjohnwu.magisk.ktx.reflectField import com.topjohnwu.magisk.ktx.set import com.topjohnwu.magisk.utils.Utils import kotlin.random.Random @@ -43,6 +45,15 @@ abstract class BaseActivity : AppCompatActivity() { super.attachBaseContext(base.wrap(true)) } + override fun onCreate(savedInstanceState: Bundle?) { + // Overwrite private members to avoid nasty "false" stack traces being logged + val delegate = delegate + val clz = delegate.javaClass + clz.reflectField("mActivityHandlesUiModeChecked").set(delegate, true) + clz.reflectField("mActivityHandlesUiMode").set(delegate, false) + super.onCreate(savedInstanceState) + } + fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) { val request = PermissionRequestBuilder().apply(builder).build() diff --git a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt index 07705f78e..a3a725515 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt @@ -5,6 +5,7 @@ import timber.log.Timber import java.io.File import java.io.InputStream import java.io.OutputStream +import java.lang.reflect.Field import java.text.SimpleDateFormat import java.util.* import java.util.zip.ZipEntry @@ -48,3 +49,6 @@ fun MutableMap.synchronized() = Collections.synchronizedMap(this) fun SimpleDateFormat.parseOrNull(date: String) = runCatching { parse(date) }.onFailure { Timber.e(it) }.getOrNull() + +fun Class<*>.reflectField(name: String): Field = + getDeclaredField(name).apply { isAccessible = true } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/CheckSafetyNetEvent.kt b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/CheckSafetyNetEvent.kt index f77e27668..fc8e0d820 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/CheckSafetyNetEvent.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/CheckSafetyNetEvent.kt @@ -13,6 +13,7 @@ import com.topjohnwu.magisk.arch.ViewEventWithScope import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.data.repository.NetworkService import com.topjohnwu.magisk.ktx.createClassLoader +import com.topjohnwu.magisk.ktx.reflectField import com.topjohnwu.magisk.ktx.writeTo import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.signing.CryptoUtils @@ -31,7 +32,6 @@ import timber.log.Timber import java.io.ByteArrayInputStream import java.io.File import java.io.IOException -import java.lang.reflect.Field import java.lang.reflect.InvocationHandler import java.security.GeneralSecurityException import java.security.SecureRandom @@ -100,14 +100,11 @@ class CheckSafetyNetEvent( helper.attest(nonce) } - private fun Class<*>.field(name: String): Field = - getDeclaredField(name).apply { isAccessible = true } - // All of these fields are whitelisted private fun BaseDexClassLoader.getDexFiles(): List { - val pathList = BaseDexClassLoader::class.java.field("pathList").get(this) - val dexElements = pathList.javaClass.field("dexElements").get(pathList) as Array<*> - val fileField = dexElements.javaClass.componentType.field("dexFile") + val pathList = BaseDexClassLoader::class.java.reflectField("pathList").get(this) + val dexElements = pathList.javaClass.reflectField("dexElements").get(pathList) as Array<*> + val fileField = dexElements.javaClass.componentType.reflectField("dexFile") return dexElements.map { fileField.get(it) as DexFile } }