mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-13 11:51:50 +00:00
Move SplashActivity logic into core module
This commit is contained in:
@@ -63,7 +63,7 @@ dependencies {
|
||||
implementation("androidx.room:room-ktx:${vRoom}")
|
||||
ksp("androidx.room:room-compiler:${vRoom}")
|
||||
|
||||
api("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.activity:activity:1.9.0")
|
||||
implementation("androidx.collection:collection-ktx:1.4.1")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.app.LocaleManager
|
||||
@@ -12,24 +11,15 @@ import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Bundle
|
||||
import android.system.Os
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.profileinstaller.ProfileInstaller
|
||||
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.launchPackage
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||
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.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.superuser.ipc.RootService
|
||||
@@ -38,8 +28,6 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.asExecutor
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@@ -141,71 +129,3 @@ object AppContext : ContextWrapper(null),
|
||||
override fun onLowMemory() {}
|
||||
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(AppMigration.PLACEHOLDER))
|
||||
) {
|
||||
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
|
||||
if (granted) {
|
||||
lifecycleScope.launch {
|
||||
val apk = File(cacheDir, "stub.apk")
|
||||
try {
|
||||
assets.open("stub.apk").writeTo(apk)
|
||||
AppMigration.upgradeStub(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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.topjohnwu.magisk.core.base
|
||||
|
||||
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.StubApk
|
||||
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.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
interface SplashScreenHost : IActivityExtension {
|
||||
val splashController: SplashController<*>
|
||||
|
||||
fun onCreateUi(savedInstanceState: Bundle?)
|
||||
fun showInvalidStateMessage()
|
||||
}
|
||||
|
||||
class SplashController<T>(private val activity: T)
|
||||
where T : ComponentActivity, T: SplashScreenHost {
|
||||
|
||||
companion object {
|
||||
private var splashShown = false
|
||||
}
|
||||
|
||||
private var shouldCreateUiOnResume = false
|
||||
|
||||
fun preOnCreate() {
|
||||
if (isRunningAsStub && !splashShown) {
|
||||
// Manually apply splash theme for stub
|
||||
activity.theme.applyStyle(R.style.StubSplashTheme, true)
|
||||
}
|
||||
}
|
||||
|
||||
fun onCreate(savedInstanceState: Bundle?) {
|
||||
if (!isRunningAsStub) {
|
||||
val splashScreen = activity.installSplashScreen()
|
||||
splashScreen.setKeepOnScreenCondition { !splashShown }
|
||||
}
|
||||
|
||||
if (splashShown) {
|
||||
doCreateUi(savedInstanceState)
|
||||
} else {
|
||||
Shell.getShell(Shell.EXECUTOR) {
|
||||
if (isRunningAsStub && !it.isRoot) {
|
||||
activity.showInvalidStateMessage()
|
||||
return@getShell
|
||||
}
|
||||
activity.initializeApp()
|
||||
activity.runOnUiThread {
|
||||
splashShown = true
|
||||
if (isRunningAsStub) {
|
||||
// Re-launch main activity without splash theme
|
||||
activity.relaunch()
|
||||
} else {
|
||||
if (activity.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||
doCreateUi(savedInstanceState)
|
||||
} else {
|
||||
shouldCreateUiOnResume = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
if (shouldCreateUiOnResume) {
|
||||
doCreateUi(null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCreateUi(savedInstanceState: Bundle?) {
|
||||
shouldCreateUiOnResume = false
|
||||
activity.onCreateUi(savedInstanceState)
|
||||
}
|
||||
|
||||
private fun T.initializeApp() {
|
||||
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(AppMigration.PLACEHOLDER))
|
||||
) {
|
||||
withPermission(REQUEST_INSTALL_PACKAGES) { granted ->
|
||||
if (granted) {
|
||||
lifecycleScope.launch {
|
||||
val apk = File(cacheDir, "stub.apk")
|
||||
try {
|
||||
assets.open("stub.apk").writeTo(apk)
|
||||
AppMigration.upgradeStub(activity, 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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user