Commit 48e2d6a8 authored by topjohnwu's avatar topjohnwu

Simplify several hacks

parent b4120cdd
...@@ -7,12 +7,8 @@ import android.content.Context ...@@ -7,12 +7,8 @@ import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.core.utils.DispatcherExecutor import com.topjohnwu.magisk.core.utils.*
import com.topjohnwu.magisk.core.utils.RootRegistry
import com.topjohnwu.magisk.core.utils.ShellInit
import com.topjohnwu.magisk.core.utils.updateConfig
import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ktx.unwrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.ipc.RootService import com.topjohnwu.superuser.ipc.RootService
...@@ -40,28 +36,34 @@ open class App() : Application() { ...@@ -40,28 +36,34 @@ open class App() : Application() {
} }
} }
override fun attachBaseContext(base: Context) { override fun attachBaseContext(context: Context) {
Shell.setDefaultBuilder(Shell.Builder.create() Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER) .setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java) .setInitializers(ShellInit::class.java)
.setTimeout(2)) .setTimeout(2))
Shell.EXECUTOR = DispatcherExecutor(Dispatchers.IO) Shell.EXECUTOR = DispatcherExecutor(Dispatchers.IO)
// Some context magic // Get the actual ContextImpl
val app: Application val app: Application
val impl: Context val base: Context
if (base is Application) { if (context is Application) {
app = base app = context
impl = base.baseContext base = context.baseContext
} else { } else {
app = this app = this
impl = base base = context
} }
val wrapped = impl.wrap() super.attachBaseContext(base)
super.attachBaseContext(wrapped) ServiceLocator.context = base
ServiceLocator.context = wrapped refreshLocale()
AssetHack.init(impl) AppApkPath = if (isRunningAsStub) {
DynAPK.current(base).path
} else {
base.packageResourcePath
}
base.resources.patch()
app.registerActivityLifecycleCallbacks(ForegroundTracker) app.registerActivityLifecycleCallbacks(ForegroundTracker)
} }
...@@ -74,14 +76,9 @@ open class App() : Application() { ...@@ -74,14 +76,9 @@ open class App() : Application() {
) )
} }
// This is required as some platforms expect ContextImpl
override fun getBaseContext(): Context {
return super.getBaseContext().unwrap()
}
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
if (resources.configuration.diff(newConfig) != 0) { if (resources.configuration.diff(newConfig) != 0) {
resources.updateConfig(newConfig) resources.setConfig(newConfig)
} }
if (!isRunningAsStub) if (!isRunningAsStub)
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
......
...@@ -13,71 +13,47 @@ import android.content.res.Resources ...@@ -13,71 +13,47 @@ import android.content.res.Resources
import android.util.DisplayMetrics import android.util.DisplayMetrics
import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.DynAPK
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.utils.refreshLocale import com.topjohnwu.magisk.core.utils.syncLocale
import com.topjohnwu.magisk.core.utils.updateConfig import com.topjohnwu.magisk.di.AppContext
fun AssetManager.addAssetPath(path: String) { lateinit var AppApkPath: String
DynAPK.addAssetPath(this, path)
}
fun Context.wrap(inject: Boolean = false): Context = fun AssetManager.addAssetPath(path: String) = DynAPK.addAssetPath(this, path)
if (inject) ReInjectedContext(this) else InjectedContext(this)
fun Class<*>.cmp(pkg: String) = fun Context.wrap(): Context = if (this is PatchedContext) this else PatchedContext(this)
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
inline fun <reified T> Activity.redirect() = Intent(intent) private class PatchedContext(base: Context) : ContextWrapper(base) {
.setComponent(T::class.java.cmp(packageName)) init { base.resources.patch() }
.setFlags(0)
inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cmp(packageName))
private open class InjectedContext(base: Context) : ContextWrapper(base) {
open val res: Resources get() = AssetHack.resource
override fun getAssets(): AssetManager = res.assets
override fun getResources() = res
override fun getClassLoader() = javaClass.classLoader!! override fun getClassLoader() = javaClass.classLoader!!
override fun createConfigurationContext(config: Configuration): Context { override fun createConfigurationContext(config: Configuration) =
return super.createConfigurationContext(config).wrap(true) super.createConfigurationContext(config).wrap()
}
} }
private class ReInjectedContext(base: Context) : InjectedContext(base) { fun Resources.patch(): Resources {
override val res by lazy { base.resources.patch() } syncLocale()
private fun Resources.patch(): Resources {
updateConfig()
if (isRunningAsStub) if (isRunningAsStub)
assets.addAssetPath(AssetHack.apk) assets.addAssetPath(AppApkPath)
return this return this
}
} }
object AssetHack { fun createNewResources(): Resources {
lateinit var resource: Resources
lateinit var apk: String
fun init(context: Context) {
resource = context.resources
refreshLocale()
if (isRunningAsStub) {
apk = DynAPK.current(context).path
resource.assets.addAssetPath(apk)
} else {
apk = context.packageResourcePath
}
}
fun newResource(): Resources {
val asset = AssetManager::class.java.newInstance() val asset = AssetManager::class.java.newInstance()
asset.addAssetPath(apk) asset.addAssetPath(AppApkPath)
val config = Configuration(resource.configuration) val config = Configuration(AppContext.resources.configuration)
val metrics = DisplayMetrics() val metrics = DisplayMetrics()
metrics.setTo(resource.displayMetrics) metrics.setTo(AppContext.resources.displayMetrics)
return Resources(asset, metrics, config) return Resources(asset, metrics, config)
}
} }
fun Class<*>.cmp(pkg: String) =
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
inline fun <reified T> Activity.redirect() = Intent(intent)
.setComponent(T::class.java.cmp(packageName))
.setFlags(0)
inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cmp(packageName))
// Keep a reference to these resources to prevent it from // Keep a reference to these resources to prevent it from
// being removed when running "remove unused resources" // being removed when running "remove unused resources"
val shouldKeepResources = listOf( val shouldKeepResources = listOf(
......
...@@ -36,7 +36,7 @@ abstract class BaseActivity : AppCompatActivity() { ...@@ -36,7 +36,7 @@ abstract class BaseActivity : AppCompatActivity() {
} }
override fun attachBaseContext(base: Context) { override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap(true)) super.attachBaseContext(base.wrap())
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
......
...@@ -422,7 +422,7 @@ abstract class MagiskInstallImpl protected constructor( ...@@ -422,7 +422,7 @@ abstract class MagiskInstallImpl protected constructor(
protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess protected fun fixEnv() = extractFiles() && "fix_env $installDir".sh().isSuccess
protected fun uninstall() = "run_uninstaller ${AssetHack.apk}".sh().isSuccess protected fun uninstall() = "run_uninstaller $AppApkPath".sh().isSuccess
@WorkerThread @WorkerThread
protected abstract suspend fun operations(): Boolean protected abstract suspend fun operations(): Boolean
......
...@@ -6,8 +6,9 @@ import android.annotation.SuppressLint ...@@ -6,8 +6,9 @@ import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.AssetHack
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.createNewResources
import com.topjohnwu.magisk.di.AppContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.util.* import java.util.*
...@@ -25,7 +26,7 @@ withContext(Dispatchers.Default) { ...@@ -25,7 +26,7 @@ withContext(Dispatchers.Default) {
val compareId = R.string.app_changelog val compareId = R.string.app_changelog
// Create a completely new resource to prevent cross talk over active configs // Create a completely new resource to prevent cross talk over active configs
val res = AssetHack.newResource() val res = createNewResources()
val locales = ArrayList<String>().apply { val locales = ArrayList<String>().apply {
// Add default locale // Add default locale
...@@ -40,13 +41,13 @@ withContext(Dispatchers.Default) { ...@@ -40,13 +41,13 @@ withContext(Dispatchers.Default) {
}.map { }.map {
Locale.forLanguageTag(it) Locale.forLanguageTag(it)
}.distinctBy { }.distinctBy {
res.updateLocale(it) res.setLocale(it)
res.getString(compareId) res.getString(compareId)
}.sortedWith { a, b -> }.sortedWith { a, b ->
a.getDisplayName(a).compareTo(b.getDisplayName(b), true) a.getDisplayName(a).compareTo(b.getDisplayName(b), true)
} }
res.updateLocale(defaultLocale) res.setLocale(defaultLocale)
val defName = res.getString(R.string.system_default) val defName = res.getString(R.string.system_default)
val names = ArrayList<String>(locales.size + 1) val names = ArrayList<String>(locales.size + 1)
...@@ -63,12 +64,14 @@ withContext(Dispatchers.Default) { ...@@ -63,12 +64,14 @@ withContext(Dispatchers.Default) {
(names.toTypedArray() to values.toTypedArray()).also { cachedLocales = it } (names.toTypedArray() to values.toTypedArray()).also { cachedLocales = it }
} }
fun Resources.updateConfig(config: Configuration = configuration) { fun Resources.setConfig(config: Configuration) {
config.setLocale(currentLocale) config.setLocale(currentLocale)
updateConfiguration(config, displayMetrics) updateConfiguration(config, displayMetrics)
} }
fun Resources.updateLocale(locale: Locale) { fun Resources.syncLocale() = setConfig(configuration)
fun Resources.setLocale(locale: Locale) {
configuration.setLocale(locale) configuration.setLocale(locale)
updateConfiguration(configuration, displayMetrics) updateConfiguration(configuration, displayMetrics)
} }
...@@ -80,5 +83,5 @@ fun refreshLocale() { ...@@ -80,5 +83,5 @@ fun refreshLocale() {
else -> Locale.forLanguageTag(localeConfig) else -> Locale.forLanguageTag(localeConfig)
} }
Locale.setDefault(currentLocale) Locale.setDefault(currentLocale)
AssetHack.resource.updateConfig() AppContext.resources.syncLocale()
} }
...@@ -41,10 +41,10 @@ import androidx.lifecycle.lifecycleScope ...@@ -41,10 +41,10 @@ import androidx.lifecycle.lifecycleScope
import androidx.transition.AutoTransition import androidx.transition.AutoTransition
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.AssetHack
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.utils.currentLocale import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.magisk.utils.DynamicClassLoader import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
...@@ -342,7 +342,7 @@ var TextView.precomputedText: CharSequence ...@@ -342,7 +342,7 @@ var TextView.precomputedText: CharSequence
} }
fun Int.dpInPx(): Int { fun Int.dpInPx(): Int {
val scale = AssetHack.resource.displayMetrics.density val scale = AppContext.resources.displayMetrics.density
return (this * scale + 0.5).toInt() return (this * scale + 0.5).toInt()
} }
......
...@@ -15,7 +15,7 @@ import android.widget.TextView ...@@ -15,7 +15,7 @@ import android.widget.TextView
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import com.caverock.androidsvg.SVG import com.caverock.androidsvg.SVG
import com.caverock.androidsvg.SVGParseException import com.caverock.androidsvg.SVGParseException
import com.topjohnwu.magisk.core.AssetHack import com.topjohnwu.magisk.di.AppContext
import com.topjohnwu.superuser.internal.WaitRunnable import com.topjohnwu.superuser.internal.WaitRunnable
import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.MarkwonSpansFactory import io.noties.markwon.MarkwonSpansFactory
...@@ -216,7 +216,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() { ...@@ -216,7 +216,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() {
return PictureDrawable(picture) return PictureDrawable(picture)
} }
val density: Float = AssetHack.resource.displayMetrics.density val density: Float = AppContext.resources.displayMetrics.density
val width = (w * density + .5f).toInt() val width = (w * density + .5f).toInt()
val height = (h * density + .5f).toInt() val height = (h * density + .5f).toInt()
...@@ -226,7 +226,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() { ...@@ -226,7 +226,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() {
canvas.scale(density, density) canvas.scale(density, density)
svg.renderToCanvas(canvas) svg.renderToCanvas(canvas)
return BitmapDrawable(AssetHack.resource, bitmap) return BitmapDrawable(AppContext.resources, bitmap)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment