mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 02:25:28 +00:00
Simplify several hacks
This commit is contained in:
parent
b4120cddfb
commit
48e2d6a8da
@ -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() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,15 +13,37 @@ 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 AssetManager.addAssetPath(path: String) = DynAPK.addAssetPath(this, path)
|
||||||
|
|
||||||
|
fun Context.wrap(): Context = if (this is PatchedContext) this else PatchedContext(this)
|
||||||
|
|
||||||
|
private class PatchedContext(base: Context) : ContextWrapper(base) {
|
||||||
|
init { base.resources.patch() }
|
||||||
|
override fun getClassLoader() = javaClass.classLoader!!
|
||||||
|
override fun createConfigurationContext(config: Configuration) =
|
||||||
|
super.createConfigurationContext(config).wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.wrap(inject: Boolean = false): Context =
|
fun Resources.patch(): Resources {
|
||||||
if (inject) ReInjectedContext(this) else InjectedContext(this)
|
syncLocale()
|
||||||
|
if (isRunningAsStub)
|
||||||
|
assets.addAssetPath(AppApkPath)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createNewResources(): Resources {
|
||||||
|
val asset = AssetManager::class.java.newInstance()
|
||||||
|
asset.addAssetPath(AppApkPath)
|
||||||
|
val config = Configuration(AppContext.resources.configuration)
|
||||||
|
val metrics = DisplayMetrics()
|
||||||
|
metrics.setTo(AppContext.resources.displayMetrics)
|
||||||
|
return Resources(asset, metrics, config)
|
||||||
|
}
|
||||||
|
|
||||||
fun Class<*>.cmp(pkg: String) =
|
fun Class<*>.cmp(pkg: String) =
|
||||||
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
|
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
|
||||||
@ -32,52 +54,6 @@ inline fun <reified T> Activity.redirect() = Intent(intent)
|
|||||||
|
|
||||||
inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cmp(packageName))
|
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 createConfigurationContext(config: Configuration): Context {
|
|
||||||
return super.createConfigurationContext(config).wrap(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ReInjectedContext(base: Context) : InjectedContext(base) {
|
|
||||||
override val res by lazy { base.resources.patch() }
|
|
||||||
private fun Resources.patch(): Resources {
|
|
||||||
updateConfig()
|
|
||||||
if (isRunningAsStub)
|
|
||||||
assets.addAssetPath(AssetHack.apk)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object AssetHack {
|
|
||||||
|
|
||||||
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()
|
|
||||||
asset.addAssetPath(apk)
|
|
||||||
val config = Configuration(resource.configuration)
|
|
||||||
val metrics = DisplayMetrics()
|
|
||||||
metrics.setTo(resource.displayMetrics)
|
|
||||||
return Resources(asset, metrics, config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(
|
|||||||
|
|
||||||
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
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}.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) {
|
|||||||
(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() {
|
|||||||
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
|
|||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
canvas.scale(density, density)
|
canvas.scale(density, density)
|
||||||
svg.renderToCanvas(canvas)
|
svg.renderToCanvas(canvas)
|
||||||
|
|
||||||
return BitmapDrawable(AssetHack.resource, bitmap)
|
return BitmapDrawable(AppContext.resources, bitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user