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.Info
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.di.ServiceLocator
import com.topjohnwu.magisk.core.isRunningAsStub
@ -113,15 +113,11 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
}
private fun initialize(savedState: Bundle?) {
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)?.let {
// Make sure the calling package matches (prevent DoS)
if (it == realCallingPackage)
it
else
null
}
val prevPkg = launchPackage
val prevConfig = intent.getBundleExtra(Const.Key.PREV_CONFIG)
val isPackageMigration = prevPkg != null && prevConfig != null
Config.load(prevPkg)
Config.init(prevConfig)
if (packageName != APP_PACKAGE_NAME) {
runCatching {
@ -130,14 +126,15 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
Shell.cmd("(pm uninstall $APP_PACKAGE_NAME)& >/dev/null 2>&1").exec()
}
} else {
if (Config.suManager.isNotEmpty())
if (Config.suManager.isNotEmpty()) {
Config.suManager = ""
if (prevPkg != null) {
}
if (isPackageMigration) {
Shell.cmd("(pm uninstall $prevPkg)& >/dev/null 2>&1").exec()
}
}
if (prevPkg != null) {
if (isPackageMigration) {
runOnUiThread {
// Relaunch the process after package migration
StubApk.restartProcess(this)

View File

@ -1,17 +1,12 @@
package com.topjohnwu.magisk.core
import android.annotation.SuppressLint
import android.os.Bundle
import androidx.core.content.edit
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.PreferenceConfig
import com.topjohnwu.magisk.core.utils.LocaleSetting
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.runBlocking
import java.io.File
import java.io.IOException
object Config : PreferenceConfig, DBConfig {
@ -20,14 +15,6 @@ object Config : PreferenceConfig, DBConfig {
override val context get() = ServiceLocator.deContext
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 {
// db configs
const val ROOT_ACCESS = "root_access"
@ -56,6 +43,9 @@ object Config : PreferenceConfig, DBConfig {
const val ASKED_HOME = "asked_home"
const val DOH = "doh"
const val RAND_NAME = "rand_name"
val NO_MIGRATION = setOf(ASKED_HOME, SU_REQUEST_TIMEOUT,
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
}
object Value {
@ -159,17 +149,37 @@ object Config : PreferenceConfig, DBConfig {
private const val SU_FINGERPRINT = "su_fingerprint"
fun load(pkg: String?) {
// Only try to load prefs when fresh install and a previous package name is set
if (pkg != null && prefs.all.isEmpty()) {
runBlocking {
try {
context.contentResolver
.openInputStream(Provider.preferencesUri(pkg))
?.writeTo(prefsFile, dispatcher = Dispatchers.Unconfined)
} catch (ignored: IOException) {}
fun toBundle(): Bundle {
val map = prefs.all - Key.NO_MIGRATION
return Bundle().apply {
for ((key, value) in map) {
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
}
}
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 {

View File

@ -54,7 +54,7 @@ object Const {
object Key {
// intents
const val OPEN_SECTION = "section"
const val PREV_PKG = "prev_pkg"
const val PREV_CONFIG = "prev_config"
}
object Value {

View File

@ -1,9 +1,6 @@
package com.topjohnwu.magisk.core
import android.net.Uri
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.su.SuCallbackHandler
import com.topjohnwu.magisk.core.su.TestHandler
@ -19,16 +16,4 @@ class Provider : BaseProvider() {
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) {
Activity::class.java.reflectField("mReferrer")
}
val Activity.realCallingPackage: String? get() {
callingPackage?.let { return it }
mReferrerField.get(this)?.let { return it as String }
return null
val Activity.launchPackage: String? get() {
return if (Build.VERSION.SDK_INT >= 34) {
launchedFromPackage
} else {
Activity::class.java.reflectField("mReferrer").get(this) as String?
}
}
fun Activity.relaunch() {

View File

@ -35,36 +35,17 @@ interface PreferenceConfig {
commit: Boolean = false
) = BooleanProperty(name, default, commit)
fun preference(
name: String,
default: Float,
commit: Boolean = false
) = FloatProperty(name, default, commit)
fun preference(
name: String,
default: Int,
commit: Boolean = false
) = IntProperty(name, default, commit)
fun preference(
name: String,
default: Long,
commit: Boolean = false
) = LongProperty(name, default, commit)
fun preference(
name: String,
default: String,
commit: Boolean = false
) = StringProperty(name, default, commit)
fun preference(
name: String,
default: Set<String>,
commit: Boolean = false
) = StringSetProperty(name, default, commit)
}
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(
private val name: String,
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(
private val name: String,
private val default: String,
@ -204,27 +137,3 @@ class StringProperty(
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
import android.app.Activity
import android.app.ActivityOptions
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast
import androidx.annotation.WorkerThread
import com.topjohnwu.magisk.StubApk
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.Provider
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.ktx.await
import com.topjohnwu.magisk.core.ktx.copyAndClose
@ -161,11 +162,12 @@ object HideAPK {
private fun launchApp(activity: Activity, pkg: String) {
val intent = activity.packageManager.getLaunchIntentForPackage(pkg) ?: return
val self = activity.packageName
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
activity.grantUriPermission(pkg, Provider.preferencesUri(self), flag)
intent.putExtra(Const.Key.PREV_PKG, self)
activity.startActivity(intent)
intent.putExtra(Const.Key.PREV_CONFIG, Config.toBundle())
val options = ActivityOptions.makeBasic()
if (Build.VERSION.SDK_INT >= 34) {
options.setShareIdentityEnabled(true)
}
activity.startActivity(intent, options.toBundle())
activity.finish()
}