Create singleton AppContext

This commit is contained in:
topjohnwu 2024-07-09 17:19:26 -07:00
parent 69181a6b72
commit 88e8e15607
19 changed files with 148 additions and 134 deletions

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.core.download.Subject

View File

@ -6,7 +6,7 @@ import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.ktx.concurrentMap
import com.topjohnwu.magisk.databinding.bindExtra
import com.topjohnwu.magisk.databinding.filterList

View File

@ -13,12 +13,12 @@ import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.repository.NetworkService
import com.topjohnwu.magisk.databinding.set

View File

@ -3,7 +3,7 @@ package com.topjohnwu.magisk.ui.log
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.ktx.timeDateFormat
import com.topjohnwu.magisk.core.ktx.toTime
import com.topjohnwu.magisk.core.model.su.SuLog

View File

@ -7,11 +7,11 @@ import androidx.core.content.pm.ShortcutManagerCompat
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.activity
import com.topjohnwu.magisk.core.ktx.toast

View File

@ -9,11 +9,11 @@ import androidx.databinding.ObservableArrayList
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.getLabel
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.core.utils.currentLocale

View File

@ -18,10 +18,10 @@ import androidx.databinding.Bindable
import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.getLabel
import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW

View File

@ -1,32 +1,9 @@
package com.topjohnwu.magisk.core
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.system.Os
import androidx.profileinstaller.ProfileInstaller
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.base.UntrackedActivity
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.utils.NetworkObserver
import com.topjohnwu.magisk.core.utils.ProcessLifecycle
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.core.utils.ShellInit
import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.core.utils.setConfig
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.ipc.RootService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.launch
import timber.log.Timber
import java.lang.ref.WeakReference
import kotlin.system.exitProcess
open class App() : Application() {
@ -39,94 +16,12 @@ open class App() : Application() {
Info.stub = data
}
init {
// Always log full stack trace with Timber
Timber.plant(Timber.DebugTree())
Thread.setDefaultUncaughtExceptionHandler { _, e ->
Timber.e(e)
exitProcess(1)
}
Os.setenv("PATH", "${Os.getenv("PATH")}:/debug_ramdisk:/sbin", true)
}
override fun attachBaseContext(context: Context) {
// Get the actual ContextImpl
val app: Application
val base: Context
if (context is Application) {
app = context
base = context.baseContext
AppApkPath = StubApk.current(base).path
AppContext.attachApplication(context)
} else {
app = this
base = context
AppApkPath = base.packageResourcePath
}
super.attachBaseContext(base)
ServiceLocator.context = base
app.registerActivityLifecycleCallbacks(ActivityTracker)
val shellBuilder = Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java)
.setContext(base)
.setTimeout(2)
Shell.setDefaultBuilder(shellBuilder)
Shell.EXECUTOR = Dispatchers.IO.asExecutor()
RootUtils.bindTask = RootService.bindOrTask(
intent<RootUtils>(),
UiThreadHandler.executor,
RootUtils.Connection
)
// Pre-heat the shell ASAP
Shell.getShell(null) {}
refreshLocale()
resources.patch()
Notifications.setup()
}
override fun onCreate() {
super.onCreate()
ProcessLifecycle.init(this)
NetworkObserver.init(this)
if (!BuildConfig.DEBUG && !isRunningAsStub) {
GlobalScope.launch(Dispatchers.IO) {
ProfileInstaller.writeProfile(this@App)
super.attachBaseContext(context)
AppContext.attachApplication(this)
}
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
if (resources.configuration.diff(newConfig) != 0) {
resources.setConfig(newConfig)
}
if (!isRunningAsStub)
super.onConfigurationChanged(newConfig)
}
}
object ActivityTracker : Application.ActivityLifecycleCallbacks {
val foreground: Activity? get() = ref.get()
@Volatile
private var ref = WeakReference<Activity>(null)
override fun onActivityResumed(activity: Activity) {
if (activity is UntrackedActivity) return
ref = WeakReference(activity)
}
override fun onActivityPaused(activity: Activity) {
if (activity is UntrackedActivity) return
ref.clear()
}
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
}

View File

@ -0,0 +1,125 @@
package com.topjohnwu.magisk.core
import android.app.Activity
import android.app.Application
import android.content.ComponentCallbacks2
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import android.system.Os
import androidx.profileinstaller.ProfileInstaller
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.base.UntrackedActivity
import com.topjohnwu.magisk.core.utils.NetworkObserver
import com.topjohnwu.magisk.core.utils.ProcessLifecycle
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.core.utils.ShellInit
import com.topjohnwu.magisk.core.utils.refreshLocale
import com.topjohnwu.magisk.core.utils.setConfig
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.ipc.RootService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.launch
import timber.log.Timber
import java.lang.ref.WeakReference
import kotlin.system.exitProcess
object AppContext : ContextWrapper(null),
Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
val foregroundActivity: Activity? get() = ref.get()
@Volatile
private var ref = WeakReference<Activity>(null)
private lateinit var application: Application
init {
// Always log full stack trace with Timber
Timber.plant(Timber.DebugTree())
Thread.setDefaultUncaughtExceptionHandler { _, e ->
Timber.e(e)
exitProcess(1)
}
Os.setenv("PATH", "${Os.getenv("PATH")}:/debug_ramdisk:/sbin", true)
}
override fun onConfigurationChanged(newConfig: Configuration) {
resources.setConfig(newConfig)
}
override fun onActivityResumed(activity: Activity) {
if (activity is UntrackedActivity) return
ref = WeakReference(activity)
}
override fun onActivityPaused(activity: Activity) {
if (activity is UntrackedActivity) return
ref.clear()
}
override fun getApplicationContext() = application
fun attachApplication(app: Application) {
application = app
val base = app.baseContext
attachBaseContext(base)
app.registerActivityLifecycleCallbacks(this)
app.registerComponentCallbacks(this)
AppApkPath = if (isRunningAsStub) {
StubApk.current(base).path
} else {
base.packageResourcePath
}
refreshLocale()
resources.patch()
val shellBuilder = Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit::class.java)
.setContext(this)
.setTimeout(2)
Shell.setDefaultBuilder(shellBuilder)
Shell.EXECUTOR = Dispatchers.IO.asExecutor()
RootUtils.bindTask = RootService.bindOrTask(
intent<RootUtils>(),
UiThreadHandler.executor,
RootUtils.Connection
)
// Pre-heat the shell ASAP
Shell.getShell(null) {}
Notifications.setup()
ProcessLifecycle.init(this)
NetworkObserver.init(this)
if (!BuildConfig.DEBUG && !isRunningAsStub) {
GlobalScope.launch(Dispatchers.IO) {
ProfileInstaller.writeProfile(this@AppContext)
}
}
}
override fun createDeviceProtectedStorageContext(): Context {
return if (SDK_INT >= Build.VERSION_CODES.N) {
super.createDeviceProtectedStorageContext()
} else {
this
}
}
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
override fun onLowMemory() {}
override fun onTrimMemory(level: Int) {}
}

View File

@ -2,7 +2,6 @@ package com.topjohnwu.magisk.core
import android.annotation.SuppressLint
import androidx.core.content.edit
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.repository.DBConfig

View File

@ -11,7 +11,6 @@ import android.content.res.Configuration
import android.content.res.Resources
import android.util.DisplayMetrics
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.unwrap
import com.topjohnwu.magisk.core.utils.syncLocale

View File

@ -3,7 +3,6 @@ package com.topjohnwu.magisk.core
import android.app.KeyguardManager
import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.getProperty
import com.topjohnwu.magisk.core.model.UpdateInfo
import com.topjohnwu.magisk.core.repository.NetworkService

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.core.data.magiskdb
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.model.su.SuPolicy
import java.util.concurrent.TimeUnit

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.text.method.LinkMovementMethod
import androidx.room.Room
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.data.SuLogDatabase
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
@ -15,13 +16,10 @@ import com.topjohnwu.magisk.core.repository.NetworkService
import io.noties.markwon.Markwon
import io.noties.markwon.utils.NoCopySpannableFactory
val AppContext: Context inline get() = ServiceLocator.context
@SuppressLint("StaticFieldLeak")
object ServiceLocator {
lateinit var context: Context
val deContext by lazy { context.deviceProtectedContext }
val deContext by lazy { AppContext.deviceProtectedContext }
val timeoutPrefs by lazy { deContext.getSharedPreferences("su_timeout", 0) }
// Database
@ -32,9 +30,9 @@ object ServiceLocator {
val logRepo by lazy { LogRepository(sulogDB) }
// Networking
val okhttp by lazy { createOkHttpClient(context) }
val okhttp by lazy { createOkHttpClient(AppContext) }
val retrofit by lazy { createRetrofit(okhttp) }
val markwon by lazy { createMarkwon(context) }
val markwon by lazy { createMarkwon(AppContext) }
val networkService by lazy {
NetworkService(
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),

View File

@ -17,7 +17,7 @@ import androidx.core.content.getSystemService
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.ActivityTracker
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.JobService
import com.topjohnwu.magisk.core.R
@ -170,7 +170,7 @@ class DownloadEngine(
is Subject.Module -> handleModule(stream, subject.file)
else -> stream.copyAndClose(subject.file.outputStream())
}
val activity = ActivityTracker.foreground
val activity = AppContext.foregroundActivity
if (activity != null && subject.autoLaunch) {
notifyRemove(subject.notifyId)
subject.pendingIntent(activity)?.send()

View File

@ -2,8 +2,8 @@ package com.topjohnwu.magisk.core.tasks
import android.net.Uri
import androidx.core.net.toFile
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.displayName
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream

View File

@ -5,12 +5,11 @@ package com.topjohnwu.magisk.core.utils
import android.annotation.SuppressLint
import android.content.res.Configuration
import android.content.res.Resources
import com.topjohnwu.magisk.core.ActivityTracker
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.base.relaunch
import com.topjohnwu.magisk.core.createNewResources
import com.topjohnwu.magisk.core.di.AppContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.Locale
@ -72,7 +71,7 @@ withContext(Dispatchers.Default) {
fun Resources.setConfig(config: Configuration) {
config.setLocale(currentLocale)
updateConfiguration(config, displayMetrics)
updateConfiguration(config, null)
}
fun Resources.syncLocale() = setConfig(configuration)
@ -85,5 +84,5 @@ fun refreshLocale() {
}
Locale.setDefault(currentLocale)
AppContext.resources.syncLocale()
ActivityTracker.foreground?.relaunch()
AppContext.foregroundActivity?.relaunch()
}

View File

@ -10,8 +10,8 @@ import android.provider.OpenableColumns
import androidx.annotation.RequiresApi
import androidx.core.net.toFile
import androidx.core.net.toUri
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.di.AppContext
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException

View File

@ -9,8 +9,8 @@ import android.os.Build
import android.os.Build.VERSION.SDK_INT
import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.AppContext
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.ktx.getBitmap