From ad40e533491f1c9f4089a9415996df48c6be8b63 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 9 Nov 2019 18:17:16 -0500 Subject: [PATCH] Update hacks --- .../main/java/com/topjohnwu/magisk/Hacks.kt | 46 +++---------------- .../topjohnwu/magisk/extensions/XAndroid.kt | 3 ++ .../com/topjohnwu/magisk/extensions/XJava.kt | 37 +++++++++++++-- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index 954d4ff24..c1e0c735f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -14,6 +14,7 @@ import android.content.res.AssetManager import android.content.res.Configuration import android.content.res.Resources import androidx.annotation.RequiresApi +import com.topjohnwu.magisk.extensions.forceGetDeclaredField import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.model.update.UpdateCheckService @@ -57,14 +58,13 @@ inline fun Context.intent() = Intent().setComponent(T::class.java.cm private open class GlobalResContext(base: Context) : ContextWrapper(base) { open val mRes: Resources get() = ResourceMgr.resource - private val loader by lazy { javaClass.classLoader!! } override fun getResources(): Resources { return mRes } override fun getClassLoader(): ClassLoader { - return loader + return javaClass.classLoader!! } override fun createConfigurationContext(config: Configuration): Context { @@ -98,7 +98,7 @@ object ResourceMgr { } } -@RequiresApi(api = 28) +@RequiresApi(28) private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() { override fun schedule(job: JobInfo): Int { @@ -126,48 +126,14 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler } private fun JobInfo.patch(): JobInfo { - // We need to patch the component of JobInfo to access WorkManager SystemJobService - + // We need to swap out the service of JobInfo val name = service.className val component = ComponentName( service.packageName, Info.stub!!.classToComponent[name] ?: name) - // Clone the JobInfo except component - val builder = JobInfo.Builder(id, component) - .setExtras(extras) - .setTransientExtras(transientExtras) - .setClipData(clipData, clipGrantFlags) - .setRequiredNetwork(requiredNetwork) - .setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes) - .setRequiresCharging(isRequireCharging) - .setRequiresDeviceIdle(isRequireDeviceIdle) - .setRequiresBatteryNotLow(isRequireBatteryNotLow) - .setRequiresStorageNotLow(isRequireStorageNotLow) - .also { - triggerContentUris?.let { uris -> - for (uri in uris) - it.addTriggerContentUri(uri) - } - } - .setTriggerContentUpdateDelay(triggerContentUpdateDelay) - .setTriggerContentMaxDelay(triggerContentMaxDelay) - .setImportantWhileForeground(isImportantWhileForeground) - .setPrefetch(isPrefetch) - .setPersisted(isPersisted) - - if (isPeriodic) { - builder.setPeriodic(intervalMillis, flexMillis) - } else { - if (minLatencyMillis > 0) - builder.setMinimumLatency(minLatencyMillis) - if (maxExecutionDelayMillis > 0) - builder.setOverrideDeadline(maxExecutionDelayMillis) - } - if (!isRequireDeviceIdle) - builder.setBackoffCriteria(initialBackoffMillis, backoffPolicy) - - return builder.build() + javaClass.forceGetDeclaredField("service")?.set(this, component) + return this } } diff --git a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt index 5266230fb..7d695bc59 100644 --- a/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt @@ -26,6 +26,7 @@ import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat +import androidx.core.net.toFile import androidx.core.net.toUri import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.FileProvider @@ -306,3 +307,5 @@ fun Context.unwrap() : Context { } return context } + +fun Uri.writeTo(file: File) = toFile().copyTo(file) diff --git a/app/src/main/java/com/topjohnwu/magisk/extensions/XJava.kt b/app/src/main/java/com/topjohnwu/magisk/extensions/XJava.kt index 1f8c7c007..ebdcd6cf3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/extensions/XJava.kt +++ b/app/src/main/java/com/topjohnwu/magisk/extensions/XJava.kt @@ -1,11 +1,11 @@ package com.topjohnwu.magisk.extensions -import android.net.Uri import android.os.Build -import androidx.core.net.toFile import java.io.File import java.io.InputStream import java.io.OutputStream +import java.lang.reflect.Field +import java.lang.reflect.Method import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipInputStream @@ -19,8 +19,6 @@ fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) { } } -fun Uri.writeTo(file: File) = toFile().copyTo(file) - fun InputStream.writeTo(file: File) = withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) } @@ -100,4 +98,33 @@ fun Locale.toLangTag(): String { tag.append('-').append(variant) return tag.toString() } -} \ No newline at end of file +} + +// Reflection hacks + +private val loadClass = ClassLoader::class.java.getMethod("loadClass", String::class.java) +private val getDeclaredMethod = Class::class.java.getMethod("getDeclaredMethod", + String::class.java, arrayOf>()::class.java) +private val getDeclaredField = Class::class.java.getMethod("getDeclaredField", String::class.java) + +fun ClassLoader.forceLoadClass(name: String) = + runCatching { loadClass.invoke(this, name) }.getOrNull() as Class<*>? + +fun Class<*>.forceGetDeclaredMethod(name: String, vararg types: Class<*>) = + (runCatching { getDeclaredMethod.invoke(this, name, *types) }.getOrNull() as Method?)?.also { + it.isAccessible = true + } + +fun Class<*>.forceGetDeclaredField(name: String) = + (runCatching { getDeclaredField.invoke(this, name) }.getOrNull() as Field?)?.also { + it.isAccessible = true + } + +inline fun T.forceGetClass(name: String) = + T::class.java.classLoader?.forceLoadClass(name) + +fun Class<*>.forceGetField(name: String): Field? = + forceGetDeclaredField(name) ?: superclass?.forceGetField(name) + +fun Class<*>.forceGetMethod(name: String, vararg types: Class<*>): Method? = + forceGetDeclaredMethod(name, *types) ?: superclass?.forceGetMethod(name, *types)