mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Improve package migration
This commit is contained in:
parent
4ab7bc0d97
commit
480198dcd0
@ -17,7 +17,7 @@ import com.topjohnwu.magisk.core.Config
|
|||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.JobService
|
import com.topjohnwu.magisk.core.JobService
|
||||||
import com.topjohnwu.magisk.core.base.realCallingPackage
|
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.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
@ -113,15 +113,11 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initialize(savedState: Bundle?) {
|
private fun initialize(savedState: Bundle?) {
|
||||||
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)?.let {
|
val prevPkg = launchPackage
|
||||||
// Make sure the calling package matches (prevent DoS)
|
val prevConfig = intent.getBundleExtra(Const.Key.PREV_CONFIG)
|
||||||
if (it == realCallingPackage)
|
val isPackageMigration = prevPkg != null && prevConfig != null
|
||||||
it
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.load(prevPkg)
|
Config.init(prevConfig)
|
||||||
|
|
||||||
if (packageName != APP_PACKAGE_NAME) {
|
if (packageName != APP_PACKAGE_NAME) {
|
||||||
runCatching {
|
runCatching {
|
||||||
@ -130,14 +126,15 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||||||
Shell.cmd("(pm uninstall $APP_PACKAGE_NAME)& >/dev/null 2>&1").exec()
|
Shell.cmd("(pm uninstall $APP_PACKAGE_NAME)& >/dev/null 2>&1").exec()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Config.suManager.isNotEmpty())
|
if (Config.suManager.isNotEmpty()) {
|
||||||
Config.suManager = ""
|
Config.suManager = ""
|
||||||
if (prevPkg != null) {
|
}
|
||||||
|
if (isPackageMigration) {
|
||||||
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
|
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevPkg != null) {
|
if (isPackageMigration) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
// Relaunch the process after package migration
|
// Relaunch the process after package migration
|
||||||
StubApk.restartProcess(this)
|
StubApk.restartProcess(this)
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
package com.topjohnwu.magisk.core
|
package com.topjohnwu.magisk.core
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.os.Bundle
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
|
||||||
import com.topjohnwu.magisk.core.repository.DBConfig
|
import com.topjohnwu.magisk.core.repository.DBConfig
|
||||||
import com.topjohnwu.magisk.core.repository.PreferenceConfig
|
import com.topjohnwu.magisk.core.repository.PreferenceConfig
|
||||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
object Config : PreferenceConfig, DBConfig {
|
object Config : PreferenceConfig, DBConfig {
|
||||||
|
|
||||||
@ -20,14 +15,6 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
override val context get() = ServiceLocator.deContext
|
override val context get() = ServiceLocator.deContext
|
||||||
override val coroutineScope get() = GlobalScope
|
override val coroutineScope get() = GlobalScope
|
||||||
|
|
||||||
private val prefsFile = File("${context.filesDir.parent}/shared_prefs", "${fileName}.xml")
|
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
fun getPrefsFile(): File {
|
|
||||||
prefs.edit().remove(Key.ASKED_HOME).commit()
|
|
||||||
return prefsFile
|
|
||||||
}
|
|
||||||
|
|
||||||
object Key {
|
object Key {
|
||||||
// db configs
|
// db configs
|
||||||
const val ROOT_ACCESS = "root_access"
|
const val ROOT_ACCESS = "root_access"
|
||||||
@ -56,6 +43,9 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
const val ASKED_HOME = "asked_home"
|
const val ASKED_HOME = "asked_home"
|
||||||
const val DOH = "doh"
|
const val DOH = "doh"
|
||||||
const val RAND_NAME = "rand_name"
|
const val RAND_NAME = "rand_name"
|
||||||
|
|
||||||
|
val NO_MIGRATION = setOf(ASKED_HOME, SU_REQUEST_TIMEOUT,
|
||||||
|
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Value {
|
object Value {
|
||||||
@ -159,17 +149,37 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
|
|
||||||
private const val SU_FINGERPRINT = "su_fingerprint"
|
private const val SU_FINGERPRINT = "su_fingerprint"
|
||||||
|
|
||||||
fun load(pkg: String?) {
|
fun toBundle(): Bundle {
|
||||||
// Only try to load prefs when fresh install and a previous package name is set
|
val map = prefs.all - Key.NO_MIGRATION
|
||||||
if (pkg != null && prefs.all.isEmpty()) {
|
return Bundle().apply {
|
||||||
runBlocking {
|
for ((key, value) in map) {
|
||||||
try {
|
when (value) {
|
||||||
context.contentResolver
|
is String -> putString(key, value)
|
||||||
.openInputStream(Provider.preferencesUri(pkg))
|
is Int -> putInt(key, value)
|
||||||
?.writeTo(prefsFile, dispatcher = Dispatchers.Unconfined)
|
is Boolean -> putBoolean(key, value)
|
||||||
} catch (ignored: IOException) {}
|
}
|
||||||
}
|
}
|
||||||
return
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
private fun fromBundle(bundle: Bundle) {
|
||||||
|
val keys = bundle.keySet().apply { removeAll(Key.NO_MIGRATION) }
|
||||||
|
prefs.edit {
|
||||||
|
for (key in keys) {
|
||||||
|
when (val value = bundle.get(key)) {
|
||||||
|
is String -> putString(key, value)
|
||||||
|
is Int -> putInt(key, value)
|
||||||
|
is Boolean -> putBoolean(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun init(bundle: Bundle?) {
|
||||||
|
// Only try to load prefs when fresh install
|
||||||
|
if (bundle != null && prefs.all.isEmpty()) {
|
||||||
|
fromBundle(bundle)
|
||||||
}
|
}
|
||||||
|
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
|
@ -54,7 +54,7 @@ object Const {
|
|||||||
object Key {
|
object Key {
|
||||||
// intents
|
// intents
|
||||||
const val OPEN_SECTION = "section"
|
const val OPEN_SECTION = "section"
|
||||||
const val PREV_PKG = "prev_pkg"
|
const val PREV_CONFIG = "prev_config"
|
||||||
}
|
}
|
||||||
|
|
||||||
object Value {
|
object Value {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.core
|
package com.topjohnwu.magisk.core
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.ParcelFileDescriptor
|
|
||||||
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
|
|
||||||
import com.topjohnwu.magisk.core.base.BaseProvider
|
import com.topjohnwu.magisk.core.base.BaseProvider
|
||||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||||
import com.topjohnwu.magisk.core.su.TestHandler
|
import com.topjohnwu.magisk.core.su.TestHandler
|
||||||
@ -19,16 +16,4 @@ class Provider : BaseProvider() {
|
|||||||
else -> TestHandler.run(method)
|
else -> TestHandler.run(method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
|
||||||
return when (uri.encodedPath ?: return null) {
|
|
||||||
"/prefs_file" -> ParcelFileDescriptor.open(Config.getPrefsFile(), MODE_READ_ONLY)
|
|
||||||
else -> super.openFile(uri, mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun preferencesUri(pkg: String): Uri =
|
|
||||||
Uri.Builder().scheme("content").authority("$pkg.provider").path("prefs_file").build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -125,14 +125,12 @@ class ActivityExtension(private val activity: ComponentActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val mReferrerField by lazy(LazyThreadSafetyMode.NONE) {
|
val Activity.launchPackage: String? get() {
|
||||||
Activity::class.java.reflectField("mReferrer")
|
return if (Build.VERSION.SDK_INT >= 34) {
|
||||||
}
|
launchedFromPackage
|
||||||
|
} else {
|
||||||
val Activity.realCallingPackage: String? get() {
|
Activity::class.java.reflectField("mReferrer").get(this) as String?
|
||||||
callingPackage?.let { return it }
|
}
|
||||||
mReferrerField.get(this)?.let { return it as String }
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Activity.relaunch() {
|
fun Activity.relaunch() {
|
||||||
|
@ -35,36 +35,17 @@ interface PreferenceConfig {
|
|||||||
commit: Boolean = false
|
commit: Boolean = false
|
||||||
) = BooleanProperty(name, default, commit)
|
) = BooleanProperty(name, default, commit)
|
||||||
|
|
||||||
fun preference(
|
|
||||||
name: String,
|
|
||||||
default: Float,
|
|
||||||
commit: Boolean = false
|
|
||||||
) = FloatProperty(name, default, commit)
|
|
||||||
|
|
||||||
fun preference(
|
fun preference(
|
||||||
name: String,
|
name: String,
|
||||||
default: Int,
|
default: Int,
|
||||||
commit: Boolean = false
|
commit: Boolean = false
|
||||||
) = IntProperty(name, default, commit)
|
) = IntProperty(name, default, commit)
|
||||||
|
|
||||||
fun preference(
|
|
||||||
name: String,
|
|
||||||
default: Long,
|
|
||||||
commit: Boolean = false
|
|
||||||
) = LongProperty(name, default, commit)
|
|
||||||
|
|
||||||
fun preference(
|
fun preference(
|
||||||
name: String,
|
name: String,
|
||||||
default: String,
|
default: String,
|
||||||
commit: Boolean = false
|
commit: Boolean = false
|
||||||
) = StringProperty(name, default, commit)
|
) = StringProperty(name, default, commit)
|
||||||
|
|
||||||
fun preference(
|
|
||||||
name: String,
|
|
||||||
default: Set<String>,
|
|
||||||
commit: Boolean = false
|
|
||||||
) = StringSetProperty(name, default, commit)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class PreferenceProperty {
|
abstract class PreferenceProperty {
|
||||||
@ -109,30 +90,6 @@ class BooleanProperty(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FloatProperty(
|
|
||||||
private val name: String,
|
|
||||||
private val default: Float,
|
|
||||||
private val commit: Boolean
|
|
||||||
) : PreferenceProperty(), ReadWriteProperty<PreferenceConfig, Float> {
|
|
||||||
|
|
||||||
override operator fun getValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>
|
|
||||||
): Float {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
return thisRef.prefs.get(prefName, default)
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun setValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>,
|
|
||||||
value: Float
|
|
||||||
) {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
thisRef.prefs.edit(commit) { put(prefName, value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IntProperty(
|
class IntProperty(
|
||||||
private val name: String,
|
private val name: String,
|
||||||
private val default: Int,
|
private val default: Int,
|
||||||
@ -157,30 +114,6 @@ class IntProperty(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LongProperty(
|
|
||||||
private val name: String,
|
|
||||||
private val default: Long,
|
|
||||||
private val commit: Boolean
|
|
||||||
) : PreferenceProperty(), ReadWriteProperty<PreferenceConfig, Long> {
|
|
||||||
|
|
||||||
override operator fun getValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>
|
|
||||||
): Long {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
return thisRef.prefs.get(prefName, default)
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun setValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>,
|
|
||||||
value: Long
|
|
||||||
) {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
thisRef.prefs.edit(commit) { put(prefName, value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StringProperty(
|
class StringProperty(
|
||||||
private val name: String,
|
private val name: String,
|
||||||
private val default: String,
|
private val default: String,
|
||||||
@ -204,27 +137,3 @@ class StringProperty(
|
|||||||
thisRef.prefs.edit(commit) { put(prefName, value) }
|
thisRef.prefs.edit(commit) { put(prefName, value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StringSetProperty(
|
|
||||||
private val name: String,
|
|
||||||
private val default: Set<String>,
|
|
||||||
private val commit: Boolean
|
|
||||||
) : PreferenceProperty(), ReadWriteProperty<PreferenceConfig, Set<String>> {
|
|
||||||
|
|
||||||
override operator fun getValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>
|
|
||||||
): Set<String> {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
return thisRef.prefs.get(prefName, default)
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun setValue(
|
|
||||||
thisRef: PreferenceConfig,
|
|
||||||
property: KProperty<*>,
|
|
||||||
value: Set<String>
|
|
||||||
) {
|
|
||||||
val prefName = name.ifBlank { property.name }
|
|
||||||
thisRef.prefs.edit(commit) { put(prefName, value) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package com.topjohnwu.magisk.core.tasks
|
package com.topjohnwu.magisk.core.tasks
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.ActivityOptions
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import com.topjohnwu.magisk.StubApk
|
import com.topjohnwu.magisk.StubApk
|
||||||
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
|
import com.topjohnwu.magisk.core.BuildConfig.APP_PACKAGE_NAME
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Provider
|
|
||||||
import com.topjohnwu.magisk.core.R
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.core.ktx.await
|
import com.topjohnwu.magisk.core.ktx.await
|
||||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||||
@ -161,11 +162,12 @@ object HideAPK {
|
|||||||
|
|
||||||
private fun launchApp(activity: Activity, pkg: String) {
|
private fun launchApp(activity: Activity, pkg: String) {
|
||||||
val intent = activity.packageManager.getLaunchIntentForPackage(pkg) ?: return
|
val intent = activity.packageManager.getLaunchIntentForPackage(pkg) ?: return
|
||||||
val self = activity.packageName
|
intent.putExtra(Const.Key.PREV_CONFIG, Config.toBundle())
|
||||||
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
val options = ActivityOptions.makeBasic()
|
||||||
activity.grantUriPermission(pkg, Provider.preferencesUri(self), flag)
|
if (Build.VERSION.SDK_INT >= 34) {
|
||||||
intent.putExtra(Const.Key.PREV_PKG, self)
|
options.setShareIdentityEnabled(true)
|
||||||
activity.startActivity(intent)
|
}
|
||||||
|
activity.startActivity(intent, options.toBundle())
|
||||||
activity.finish()
|
activity.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user