Move app initialization routine into core module

This commit is contained in:
topjohnwu 2024-07-11 16:10:49 -07:00
parent 480198dcd0
commit fe9ec3bc6d
2 changed files with 94 additions and 97 deletions

View File

@ -9,31 +9,16 @@ import androidx.databinding.ViewDataBinding
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.arch.NavigationActivity import com.topjohnwu.magisk.arch.NavigationActivity
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.JobService
import com.topjohnwu.magisk.core.base.launchPackage
import com.topjohnwu.magisk.core.base.relaunch import com.topjohnwu.magisk.core.base.relaunch
import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.initializeOnSplashScreen
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.ktx.toast import com.topjohnwu.magisk.core.ktx.toast
import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.io.IOException
import com.topjohnwu.magisk.core.R as CoreR import com.topjohnwu.magisk.core.R as CoreR
@SuppressLint("CustomSplashScreen") @SuppressLint("CustomSplashScreen")
@ -68,7 +53,19 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
showInvalidStateMessage() showInvalidStateMessage()
return@getShell return@getShell
} }
initialize(savedInstanceState) initializeOnSplashScreen {
splashShown = true
if (isRunningAsStub) {
// Re-launch main activity without splash theme
relaunch()
} else {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
doShowMainUI(savedInstanceState)
} else {
needShowMainUI = true
}
}
}
} }
} }
} }
@ -111,83 +108,4 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
doShowMainUI(null) doShowMainUI(null)
} }
} }
private fun initialize(savedState: Bundle?) {
val prevPkg = launchPackage
val prevConfig = intent.getBundleExtra(Const.Key.PREV_CONFIG)
val isPackageMigration = prevPkg != null && prevConfig != null
Config.init(prevConfig)
if (packageName != APP_PACKAGE_NAME) {
runCatching {
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
packageManager.getApplicationInfo(APP_PACKAGE_NAME, 0)
Shell.cmd("(pm uninstall $APP_PACKAGE_NAME)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty()) {
Config.suManager = ""
}
if (isPackageMigration) {
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
}
}
if (isPackageMigration) {
runOnUiThread {
// Relaunch the process after package migration
StubApk.restartProcess(this)
}
return
}
// Validate stub APK
if (isRunningAsStub && (
// Version mismatch
Info.stub!!.version != BuildConfig.STUB_VERSION ||
// Not properly patched
intent.component!!.className.contains(HideAPK.PLACEHOLDER)
)) {
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
if (granted) {
lifecycleScope.launch(Dispatchers.IO) {
val apk = File(cacheDir, "stub.apk")
try {
assets.open("stub.apk").writeTo(apk)
HideAPK.upgrade(this@SplashActivity, apk)?.let {
startActivity(it)
}
} catch (e: IOException) {
Timber.e(e)
}
}
}
}
return
}
JobService.schedule(this)
Shortcuts.setupDynamic(this)
// Pre-fetch network services
ServiceLocator.networkService
// Wait for root service
RootUtils.Connection.await()
runOnUiThread {
splashShown = true
if (isRunningAsStub) {
// Re-launch main activity without splash theme
relaunch()
} else {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
doShowMainUI(savedState)
} else {
needShowMainUI = true
}
}
}
}
} }

View File

@ -1,5 +1,6 @@
package com.topjohnwu.magisk.core package com.topjohnwu.magisk.core
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.app.LocaleManager import android.app.LocaleManager
@ -11,15 +12,24 @@ import android.os.Build
import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION.SDK_INT
import android.os.Bundle import android.os.Bundle
import android.system.Os import android.system.Os
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import androidx.profileinstaller.ProfileInstaller import androidx.profileinstaller.ProfileInstaller
import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
import com.topjohnwu.magisk.core.base.IActivityExtension
import com.topjohnwu.magisk.core.base.UntrackedActivity import com.topjohnwu.magisk.core.base.UntrackedActivity
import com.topjohnwu.magisk.core.base.launchPackage
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.ktx.writeTo
import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.core.utils.LocaleSetting import com.topjohnwu.magisk.core.utils.LocaleSetting
import com.topjohnwu.magisk.core.utils.NetworkObserver import com.topjohnwu.magisk.core.utils.NetworkObserver
import com.topjohnwu.magisk.core.utils.ProcessLifecycle import com.topjohnwu.magisk.core.utils.ProcessLifecycle
import com.topjohnwu.magisk.core.utils.RootUtils import com.topjohnwu.magisk.core.utils.RootUtils
import com.topjohnwu.magisk.core.utils.ShellInit import com.topjohnwu.magisk.core.utils.ShellInit
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
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
@ -28,6 +38,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asExecutor import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.io.File
import java.io.IOException
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -39,7 +51,6 @@ object AppContext : ContextWrapper(null),
val foregroundActivity: Activity? get() = ref.get() val foregroundActivity: Activity? get() = ref.get()
@Volatile
private var ref = WeakReference<Activity>(null) private var ref = WeakReference<Activity>(null)
private lateinit var application: Application private lateinit var application: Application
@ -130,3 +141,71 @@ object AppContext : ContextWrapper(null),
override fun onLowMemory() {} override fun onLowMemory() {}
override fun onTrimMemory(level: Int) {} override fun onTrimMemory(level: Int) {}
} }
fun <T> T.initializeOnSplashScreen(launchUi: Runnable)
where T : ComponentActivity, T : IActivityExtension {
val prevPkg = launchPackage
val prevConfig = intent.getBundleExtra(Const.Key.PREV_CONFIG)
val isPackageMigration = prevPkg != null && prevConfig != null
Config.init(prevConfig)
if (packageName != APP_PACKAGE_NAME) {
runCatching {
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
packageManager.getApplicationInfo(APP_PACKAGE_NAME, 0)
Shell.cmd("(pm uninstall $APP_PACKAGE_NAME)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty()) {
Config.suManager = ""
}
if (isPackageMigration) {
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
}
}
if (isPackageMigration) {
runOnUiThread {
// Relaunch the process after package migration
StubApk.restartProcess(this)
}
return
}
// Validate stub APK
if (isRunningAsStub && (
// Version mismatch
Info.stub!!.version != BuildConfig.STUB_VERSION ||
// Not properly patched
intent.component!!.className.contains(HideAPK.PLACEHOLDER))
) {
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
if (granted) {
lifecycleScope.launch(Dispatchers.IO) {
val apk = File(cacheDir, "stub.apk")
try {
assets.open("stub.apk").writeTo(apk)
HideAPK.upgrade(this@initializeOnSplashScreen, apk)?.let {
startActivity(it)
}
} catch (e: IOException) {
Timber.e(e)
}
}
}
}
return
}
JobService.schedule(this)
Shortcuts.setupDynamic(this)
// Pre-fetch network services
ServiceLocator.networkService
// Wait for root service
RootUtils.Connection.await()
runOnUiThread(launchUi)
}