Update hacks
This commit is contained in:
parent
a2ddf362d8
commit
ad40e53349
@ -14,6 +14,7 @@ import android.content.res.AssetManager
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.topjohnwu.magisk.extensions.forceGetDeclaredField
|
||||||
import com.topjohnwu.magisk.model.download.DownloadService
|
import com.topjohnwu.magisk.model.download.DownloadService
|
||||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||||
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
||||||
@ -57,14 +58,13 @@ inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cm
|
|||||||
|
|
||||||
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
||||||
open val mRes: Resources get() = ResourceMgr.resource
|
open val mRes: Resources get() = ResourceMgr.resource
|
||||||
private val loader by lazy { javaClass.classLoader!! }
|
|
||||||
|
|
||||||
override fun getResources(): Resources {
|
override fun getResources(): Resources {
|
||||||
return mRes
|
return mRes
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getClassLoader(): ClassLoader {
|
override fun getClassLoader(): ClassLoader {
|
||||||
return loader
|
return javaClass.classLoader!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createConfigurationContext(config: Configuration): Context {
|
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() {
|
private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() {
|
||||||
|
|
||||||
override fun schedule(job: JobInfo): Int {
|
override fun schedule(job: JobInfo): Int {
|
||||||
@ -126,48 +126,14 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun JobInfo.patch(): JobInfo {
|
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 name = service.className
|
||||||
val component = ComponentName(
|
val component = ComponentName(
|
||||||
service.packageName,
|
service.packageName,
|
||||||
Info.stub!!.classToComponent[name] ?: name)
|
Info.stub!!.classToComponent[name] ?: name)
|
||||||
|
|
||||||
// Clone the JobInfo except component
|
javaClass.forceGetDeclaredField("service")?.set(this, component)
|
||||||
val builder = JobInfo.Builder(id, component)
|
return this
|
||||||
.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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import androidx.annotation.ColorRes
|
|||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toFile
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.topjohnwu.magisk.Const
|
import com.topjohnwu.magisk.Const
|
||||||
import com.topjohnwu.magisk.FileProvider
|
import com.topjohnwu.magisk.FileProvider
|
||||||
@ -306,3 +307,5 @@ fun Context.unwrap() : Context {
|
|||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Uri.writeTo(file: File) = toFile().copyTo(file)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package com.topjohnwu.magisk.extensions
|
package com.topjohnwu.magisk.extensions
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.net.toFile
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
import java.lang.reflect.Method
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
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) =
|
fun InputStream.writeTo(file: File) =
|
||||||
withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) }
|
withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) }
|
||||||
|
|
||||||
@ -100,4 +98,33 @@ fun Locale.toLangTag(): String {
|
|||||||
tag.append('-').append(variant)
|
tag.append('-').append(variant)
|
||||||
return tag.toString()
|
return tag.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<*>>()::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 <reified T> 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user