Improve package migration

This commit is contained in:
topjohnwu 2024-07-11 15:50:40 -07:00
parent 4ab7bc0d97
commit 480198dcd0
7 changed files with 58 additions and 157 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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 {

View File

@ -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()
}
} }

View File

@ -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() {

View File

@ -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) }
}
}

View File

@ -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()
} }