mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 02:48:43 +00:00
Make main app fully independent from the stub
- Skip 0x7f01XXXX - 0x7f05XXXX resource IDs in the main app; they are reserved for stub resources - Support sending additional data from host to guest - Use resource mapping passed from host when they are being sent to the system framework (notifications and shortcuts)
This commit is contained in:
parent
9f9de8c43b
commit
40eda05a30
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,7 +4,6 @@ out
|
||||
*.apk
|
||||
/config.prop
|
||||
/update.sh
|
||||
/stub-ids.txt
|
||||
|
||||
# Built binaries
|
||||
native/out
|
||||
|
5
app/res-ids.txt
Normal file
5
app/res-ids.txt
Normal file
@ -0,0 +1,5 @@
|
||||
com.topjohnwu.magisk:color/xxxxxxxx = 0x7f010000
|
||||
com.topjohnwu.magisk:drawable/xxxxxxxx = 0x7f020000
|
||||
com.topjohnwu.magisk:string/xxxxxxxx = 0x7f030000
|
||||
com.topjohnwu.magisk:style/xxxxxxxx = 0x7f040000
|
||||
com.topjohnwu.magisk:xml/xxxxxxxx = 0x7f050000
|
@ -2,14 +2,12 @@ package a;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class e extends App {
|
||||
public e() {
|
||||
super();
|
||||
}
|
||||
|
||||
public e(Map<String, String> map) {
|
||||
super(map);
|
||||
public e(Object o) {
|
||||
super(o);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import com.topjohnwu.magisk.di.ActivityTracker
|
||||
import com.topjohnwu.magisk.di.koinModules
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.unwrap
|
||||
import com.topjohnwu.magisk.utils.DynAPK
|
||||
import com.topjohnwu.magisk.utils.RootInit
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
@ -23,9 +24,8 @@ import timber.log.Timber
|
||||
|
||||
open class App() : Application() {
|
||||
|
||||
constructor(map: Map<String, String>) : this() {
|
||||
isRunningAsStub = true
|
||||
ClassMap.componentMap = map
|
||||
constructor(o: Any) : this() {
|
||||
ClassMap.data = DynAPK.load(o)
|
||||
}
|
||||
|
||||
init {
|
||||
@ -53,7 +53,6 @@ open class App() : Application() {
|
||||
val app: Application
|
||||
val impl: Context
|
||||
if (base is Application) {
|
||||
isRunningAsStub = true
|
||||
app = base
|
||||
impl = base.baseContext
|
||||
} else {
|
||||
|
@ -28,7 +28,7 @@ import com.topjohnwu.magisk.utils.currentLocale
|
||||
import com.topjohnwu.magisk.utils.defaultLocale
|
||||
import java.util.*
|
||||
|
||||
var isRunningAsStub = false
|
||||
val isRunningAsStub get() = ClassMap.data != null
|
||||
|
||||
private val addAssetPath by lazy {
|
||||
AssetManager::class.java.getMethod("addAssetPath", String::class.java)
|
||||
@ -39,10 +39,14 @@ fun AssetManager.addAssetPath(path: String) {
|
||||
}
|
||||
|
||||
fun Context.wrap(global: Boolean = true): Context
|
||||
= if (!global) ResContext(this) else GlobalResContext(this)
|
||||
= if (global) GlobalResContext(this) else ResContext(this)
|
||||
|
||||
fun Context.wrapJob(): Context = object : GlobalResContext(this) {
|
||||
|
||||
override fun getApplicationContext(): Context {
|
||||
return this
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun getSystemService(name: String): Any? {
|
||||
return if (!isRunningAsStub) super.getSystemService(name) else
|
||||
@ -65,26 +69,32 @@ private fun Resources.patch(config: Configuration = Configuration(configuration)
|
||||
|
||||
fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName {
|
||||
val name = ClassMap[this].name
|
||||
return ComponentName(pkg, ClassMap.componentMap?.get(name)
|
||||
?: name)
|
||||
return ComponentName(pkg, ClassMap.data?.componentMap?.get(name) ?: name)
|
||||
}
|
||||
|
||||
fun Context.intent(c: Class<*>): Intent {
|
||||
val cls = ClassMap[c]
|
||||
return ClassMap.componentMap?.let {
|
||||
val className = it.getOrElse(cls.name) { cls.name }
|
||||
return ClassMap.data?.let {
|
||||
val className = it.componentMap.getOrElse(cls.name) { cls.name }
|
||||
Intent().setComponent(ComponentName(this, className))
|
||||
} ?: Intent(this, cls)
|
||||
}
|
||||
|
||||
fun resolveRes(idx: Int): Int {
|
||||
return ClassMap.data?.resourceMap?.get(idx) ?: when(idx) {
|
||||
DynAPK.NOTIFICATION -> R.drawable.ic_magisk_outline
|
||||
DynAPK.DOWNLOAD -> R.drawable.sc_cloud_download
|
||||
DynAPK.SUPERUSER -> R.drawable.sc_superuser
|
||||
DynAPK.MODULES -> R.drawable.sc_extension
|
||||
DynAPK.MAGISKHIDE -> R.drawable.sc_magiskhide
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
||||
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
||||
open val mRes: Resources get() = ResourceMgr.resource
|
||||
private val loader by lazy { javaClass.classLoader!! }
|
||||
|
||||
override fun getApplicationContext(): Context {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getResources(): Resources {
|
||||
return mRes
|
||||
}
|
||||
@ -162,7 +172,7 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler
|
||||
// We need to patch the component of JobInfo to access WorkManager SystemJobService
|
||||
|
||||
val name = service.className
|
||||
val component = ComponentName(service.packageName, ClassMap.componentMap?.get(name)
|
||||
val component = ComponentName(service.packageName, ClassMap.data?.componentMap?.get(name)
|
||||
?: name)
|
||||
|
||||
// Clone the JobInfo except component
|
||||
@ -205,7 +215,7 @@ private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler
|
||||
|
||||
object ClassMap {
|
||||
|
||||
private val classMap = mapOf(
|
||||
private val map = mapOf(
|
||||
App::class.java to a.e::class.java,
|
||||
MainActivity::class.java to a.b::class.java,
|
||||
SplashActivity::class.java to a.c::class.java,
|
||||
@ -216,8 +226,7 @@ object ClassMap {
|
||||
SuRequestActivity::class.java to a.m::class.java
|
||||
)
|
||||
|
||||
// This will be set if running as guest app
|
||||
var componentMap: Map<String, String>? = null
|
||||
internal var data: DynAPK.Data? = null
|
||||
|
||||
operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() }
|
||||
operator fun get(c: Class<*>) = map.getOrElse(c) { throw IllegalArgumentException() }
|
||||
}
|
||||
|
@ -12,10 +12,12 @@ import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
import com.topjohnwu.magisk.utils.DynAPK
|
||||
|
||||
object Notifications {
|
||||
|
||||
val mgr by lazy { NotificationManagerCompat.from(get()) }
|
||||
private val icon by lazy { resolveRes(DynAPK.NOTIFICATION) }
|
||||
|
||||
fun setup(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
@ -39,7 +41,7 @@ object Notifications {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
builder.setSmallIcon(icon)
|
||||
.setContentTitle(context.getString(R.string.magisk_update_title))
|
||||
.setContentText(context.getString(R.string.manager_download_install))
|
||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||
@ -58,7 +60,7 @@ object Notifications {
|
||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
builder.setSmallIcon(icon)
|
||||
.setContentTitle(context.getString(R.string.manager_update_title))
|
||||
.setContentText(context.getString(R.string.manager_download_install))
|
||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||
@ -75,7 +77,7 @@ object Notifications {
|
||||
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
builder.setSmallIcon(icon)
|
||||
.setContentTitle(context.getString(R.string.dtbo_patched_title))
|
||||
.setContentText(context.getString(R.string.dtbo_patched_reboot))
|
||||
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||
|
@ -9,19 +9,20 @@ import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
import com.topjohnwu.magisk.utils.DynAPK
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
object Shortcuts {
|
||||
|
||||
fun setup(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
if (Build.VERSION.SDK_INT >= 25) {
|
||||
val manager = context.getSystemService(ShortcutManager::class.java)
|
||||
manager?.dynamicShortcuts = getShortCuts(context)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
|
||||
@RequiresApi(api = 25)
|
||||
private fun getShortCuts(context: Context): List<ShortcutInfo> {
|
||||
val shortCuts = mutableListOf<ShortcutInfo>()
|
||||
val root = Shell.rootAccess()
|
||||
@ -33,7 +34,7 @@ object Shortcuts {
|
||||
.putExtra(Const.Key.OPEN_SECTION, "superuser")
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||
.setIcon(Icon.createWithResource(context, R.drawable.sc_superuser))
|
||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.SUPERUSER)))
|
||||
.setRank(0)
|
||||
.build())
|
||||
}
|
||||
@ -44,7 +45,7 @@ object Shortcuts {
|
||||
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||
.setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide))
|
||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MAGISKHIDE)))
|
||||
.setRank(1)
|
||||
.build())
|
||||
}
|
||||
@ -55,7 +56,7 @@ object Shortcuts {
|
||||
.putExtra(Const.Key.OPEN_SECTION, "modules")
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||
.setIcon(Icon.createWithResource(context, R.drawable.sc_extension))
|
||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MODULES)))
|
||||
.setRank(3)
|
||||
.build())
|
||||
shortCuts.add(ShortcutInfo.Builder(context, "downloads")
|
||||
@ -64,7 +65,7 @@ object Shortcuts {
|
||||
.putExtra(Const.Key.OPEN_SECTION, "downloads")
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
|
||||
.setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download))
|
||||
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.DOWNLOAD)))
|
||||
.setRank(2)
|
||||
.build())
|
||||
}
|
||||
|
@ -8,16 +8,4 @@
|
||||
<string name="magiskhide" translatable="false">Magisk Hide</string>
|
||||
<string name="empty" translatable="false"/>
|
||||
|
||||
<!-- Preserve 10 string slots for stub -->
|
||||
<string name="stub_0" translatable="false"/>
|
||||
<string name="stub_1" translatable="false"/>
|
||||
<string name="stub_2" translatable="false"/>
|
||||
<string name="stub_3" translatable="false"/>
|
||||
<string name="stub_4" translatable="false"/>
|
||||
<string name="stub_5" translatable="false"/>
|
||||
<string name="stub_6" translatable="false"/>
|
||||
<string name="stub_7" translatable="false"/>
|
||||
<string name="stub_8" translatable="false"/>
|
||||
<string name="stub_9" translatable="false"/>
|
||||
|
||||
</resources>
|
||||
|
11
build.gradle
11
build.gradle
@ -86,12 +86,11 @@ subprojects {
|
||||
|
||||
aaptOptions {
|
||||
// Handle resource IDs
|
||||
File resIds = rootProject.file('stable-ids.txt')
|
||||
File stubIds = rootProject.file('stub-ids.txt')
|
||||
if (module.name == 'app' && resIds.exists())
|
||||
additionalParameters "--stable-ids", "${resIds.absolutePath}"
|
||||
else if (module.name == 'stub')
|
||||
additionalParameters "--emit-ids", "${stubIds.absolutePath}"
|
||||
File resId = project.file('res-ids.txt')
|
||||
if (resId.exists())
|
||||
additionalParameters "--stable-ids", "${resId.absolutePath}"
|
||||
else
|
||||
additionalParameters "--emit-ids", "${resId.absolutePath}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,21 @@ package com.topjohnwu.magisk.utils;
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
public class DynAPK {
|
||||
|
||||
// Indices of the object array
|
||||
private static final int COMPONENT_MAP = 0;
|
||||
private static final int RESOURCE_MAP = 1;
|
||||
|
||||
// Indices of the resource map
|
||||
public static final int NOTIFICATION = 0;
|
||||
public static final int DOWNLOAD = 1;
|
||||
public static final int SUPERUSER = 2;
|
||||
public static final int MODULES = 3;
|
||||
public static final int MAGISKHIDE = 4;
|
||||
|
||||
private static File dynDir;
|
||||
|
||||
private static File getDynDir(Context c) {
|
||||
@ -23,4 +35,24 @@ public class DynAPK {
|
||||
public static File update(Context c) {
|
||||
return new File(getDynDir(c), "update.apk");
|
||||
}
|
||||
|
||||
public static Data load(Object o) {
|
||||
Object[] arr = (Object[]) o;
|
||||
Data data = new Data();
|
||||
data.componentMap = (Map<String, String>) arr[COMPONENT_MAP];
|
||||
data.resourceMap = (int[]) arr[RESOURCE_MAP];
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Object pack(Data data) {
|
||||
Object[] arr = new Object[2];
|
||||
arr[COMPONENT_MAP] = data.componentMap;
|
||||
arr[RESOURCE_MAP] = data.resourceMap;
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static class Data {
|
||||
public Map<String, String> componentMap;
|
||||
public int[] resourceMap;
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
com.topjohnwu.magisk:color/dark = 0x7f010000
|
||||
com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001
|
||||
com.topjohnwu.magisk:color/light = 0x7f010002
|
||||
com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020000
|
||||
com.topjohnwu.magisk:drawable/ic_extension = 0x7f020001
|
||||
com.topjohnwu.magisk:drawable/ic_launcher = 0x7f020002
|
||||
com.topjohnwu.magisk:drawable/ic_logo = 0x7f020003
|
||||
com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020004
|
||||
com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020005
|
||||
com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f020006
|
||||
com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020007
|
||||
com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020008
|
||||
com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020009
|
||||
com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f02000a
|
||||
com.topjohnwu.magisk:drawable/sc_extension = 0x7f02000b
|
||||
com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f02000c
|
||||
com.topjohnwu.magisk:drawable/sc_superuser = 0x7f02000d
|
||||
com.topjohnwu.magisk:style/SplashTheme = 0x7f040000
|
||||
com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040001
|
||||
com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040002
|
||||
com.topjohnwu.magisk:xml/file_paths = 0x7f050000
|
||||
|
||||
com.topjohnwu.magisk:string/stub_0 = 0x7f030000
|
||||
com.topjohnwu.magisk:string/stub_1 = 0x7f030001
|
||||
com.topjohnwu.magisk:string/stub_2 = 0x7f030002
|
||||
com.topjohnwu.magisk:string/stub_3 = 0x7f030003
|
||||
com.topjohnwu.magisk:string/stub_4 = 0x7f030004
|
||||
com.topjohnwu.magisk:string/stub_5 = 0x7f030005
|
||||
com.topjohnwu.magisk:string/stub_6 = 0x7f030006
|
||||
com.topjohnwu.magisk:string/stub_7 = 0x7f030007
|
||||
com.topjohnwu.magisk:string/stub_8 = 0x7f030008
|
||||
com.topjohnwu.magisk:string/stub_9 = 0x7f030009
|
27
stub/res-ids.txt
Normal file
27
stub/res-ids.txt
Normal file
@ -0,0 +1,27 @@
|
||||
com.topjohnwu.magisk:style/SplashThemeBase.V19 = 0x7f040000
|
||||
com.topjohnwu.magisk:string/app_name = 0x7f030000
|
||||
com.topjohnwu.magisk:string/yes = 0x7f030001
|
||||
com.topjohnwu.magisk:style/SplashTheme = 0x7f040001
|
||||
com.topjohnwu.magisk:drawable/sc_superuser = 0x7f020000
|
||||
com.topjohnwu.magisk:string/no_thanks = 0x7f030002
|
||||
com.topjohnwu.magisk:drawable/ic_splash_activity = 0x7f020001
|
||||
com.topjohnwu.magisk:drawable/sc_magiskhide = 0x7f020002
|
||||
com.topjohnwu.magisk:color/light = 0x7f010000
|
||||
com.topjohnwu.magisk:string/no_internet_msg = 0x7f030003
|
||||
com.topjohnwu.magisk:drawable/sc_extension = 0x7f020003
|
||||
com.topjohnwu.magisk:drawable/ic_magisk_outline = 0x7f020004
|
||||
com.topjohnwu.magisk:color/ic_launcher_background = 0x7f010001
|
||||
com.topjohnwu.magisk:xml/file_paths = 0x7f050000
|
||||
com.topjohnwu.magisk:drawable/sc_cloud_download = 0x7f020005
|
||||
com.topjohnwu.magisk:string/ok = 0x7f030004
|
||||
com.topjohnwu.magisk:drawable/ic_magisk = 0x7f020006
|
||||
com.topjohnwu.magisk:drawable/ic_superuser = 0x7f020007
|
||||
com.topjohnwu.magisk:drawable/ic_cloud_download = 0x7f020008
|
||||
com.topjohnwu.magisk:style/SplashThemeBase = 0x7f040002
|
||||
com.topjohnwu.magisk:drawable/ic_magiskhide = 0x7f020009
|
||||
com.topjohnwu.magisk:drawable/ic_launcher = 0x7f02000a
|
||||
com.topjohnwu.magisk:drawable/ic_logo = 0x7f02000b
|
||||
com.topjohnwu.magisk:drawable/ic_extension = 0x7f02000c
|
||||
com.topjohnwu.magisk:string/upgrade_msg = 0x7f030005
|
||||
com.topjohnwu.magisk:color/dark = 0x7f010002
|
||||
com.topjohnwu.magisk:drawable/ic_magisk_padded = 0x7f02000d
|
@ -1,12 +0,0 @@
|
||||
package androidx.work.impl;
|
||||
|
||||
import com.topjohnwu.magisk.dummy.DummyProvider;
|
||||
|
||||
public class WorkManagerInitializer extends DummyProvider {
|
||||
/* This class have to exist, or else pre 9.0 devices
|
||||
* will experience ClassNotFoundException crashes when
|
||||
* launching the stub, as ContentProviders are constructed
|
||||
* when an app starts up. Pre 9.0 devices do not have
|
||||
* our custom DelegateComponentFactory to help creating
|
||||
* dummies. */
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AppComponentFactory;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
@ -13,7 +14,6 @@ import com.topjohnwu.magisk.utils.DynamicClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.topjohnwu.magisk.DownloadActivity.TAG;
|
||||
|
||||
@ -34,35 +34,7 @@ public class DelegateApplication extends Application {
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
// If 9.0+, try to dynamically load the APK
|
||||
DelegateComponentFactory factory = (DelegateComponentFactory) this.factory;
|
||||
MANAGER_APK = DynAPK.current(this);
|
||||
File update = DynAPK.update(this);
|
||||
if (update.exists())
|
||||
update.renameTo(MANAGER_APK);
|
||||
if (MANAGER_APK.exists()) {
|
||||
ClassLoader cl = new DynamicClassLoader(MANAGER_APK, factory.loader);
|
||||
try {
|
||||
// Create the delegate AppComponentFactory
|
||||
Object df = cl.loadClass("a.a").newInstance();
|
||||
|
||||
// Create the delegate Application
|
||||
delegate = (Application) cl.loadClass("a.e").getConstructor(Map.class)
|
||||
.newInstance(ComponentMap.inverseMap);
|
||||
|
||||
// Call attachBaseContext without ContextImpl to show it is being wrapped
|
||||
Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class);
|
||||
m.setAccessible(true);
|
||||
m.invoke(delegate, this);
|
||||
|
||||
// If everything went well, set our loader and delegate
|
||||
factory.delegate = (AppComponentFactory) df;
|
||||
factory.loader = cl;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "dyn load", e);
|
||||
MANAGER_APK.delete();
|
||||
}
|
||||
}
|
||||
setUpDynAPK();
|
||||
} else {
|
||||
MANAGER_APK = new File(base.getCacheDir(), "manager.apk");
|
||||
}
|
||||
@ -73,4 +45,36 @@ public class DelegateApplication extends Application {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
delegate.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void setUpDynAPK() {
|
||||
DelegateComponentFactory factory = (DelegateComponentFactory) this.factory;
|
||||
MANAGER_APK = DynAPK.current(this);
|
||||
File update = DynAPK.update(this);
|
||||
if (update.exists())
|
||||
update.renameTo(MANAGER_APK);
|
||||
if (MANAGER_APK.exists()) {
|
||||
ClassLoader cl = new DynamicClassLoader(MANAGER_APK, factory.loader);
|
||||
try {
|
||||
// Create the delegate AppComponentFactory
|
||||
Object df = cl.loadClass("a.a").newInstance();
|
||||
|
||||
// Create the delegate Application
|
||||
delegate = (Application) cl.loadClass("a.e").getConstructor(Object.class)
|
||||
.newInstance(DynAPK.pack(Mapping.data));
|
||||
|
||||
// Call attachBaseContext without ContextImpl to show it is being wrapped
|
||||
Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class);
|
||||
m.setAccessible(true);
|
||||
m.invoke(delegate, this);
|
||||
|
||||
// If everything went well, set our loader and delegate
|
||||
factory.delegate = (AppComponentFactory) df;
|
||||
factory.loader = cl;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "dyn load", e);
|
||||
MANAGER_APK.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
Log.d(TAG, className);
|
||||
if (delegate != null)
|
||||
return delegate.instantiateActivity(loader, ComponentMap.get(className), intent);
|
||||
return delegate.instantiateActivity(loader, Mapping.get(className), intent);
|
||||
return create(className, DummyActivity.class);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
Log.d(TAG, className);
|
||||
if (delegate != null)
|
||||
return delegate.instantiateReceiver(loader, ComponentMap.get(className), intent);
|
||||
return delegate.instantiateReceiver(loader, Mapping.get(className), intent);
|
||||
return create(className, DummyReceiver.class);
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
Log.d(TAG, className);
|
||||
if (delegate != null)
|
||||
return delegate.instantiateService(loader, ComponentMap.get(className), intent);
|
||||
return delegate.instantiateService(loader, Mapping.get(className), intent);
|
||||
return create(className, DummyService.class);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
||||
Log.d(TAG, className);
|
||||
if (loader == null) loader = cl;
|
||||
if (delegate != null)
|
||||
return delegate.instantiateProvider(loader, ComponentMap.get(className));
|
||||
return delegate.instantiateProvider(loader, Mapping.get(className));
|
||||
return create(className, DummyProvider.class);
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,13 @@ package com.topjohnwu.magisk;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class ComponentMap {
|
||||
import static com.topjohnwu.magisk.utils.DynAPK.*;
|
||||
|
||||
class Mapping {
|
||||
private static Map<String, String> map = new HashMap<>();
|
||||
|
||||
// This mapping will be sent into the guest app
|
||||
static Map<String, String> inverseMap;
|
||||
static Data data = new Data();
|
||||
|
||||
static {
|
||||
map.put(a.z.class.getName(), "a.c");
|
||||
@ -18,10 +20,17 @@ class ComponentMap {
|
||||
map.put("a.v", "a.j");
|
||||
map.put("a.j", "androidx.work.impl.background.systemjob.SystemJobService");
|
||||
|
||||
inverseMap = new HashMap<>(map.size());
|
||||
data.componentMap = new HashMap<>(map.size());
|
||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||
inverseMap.put(e.getValue(), e.getKey());
|
||||
data.componentMap.put(e.getValue(), e.getKey());
|
||||
}
|
||||
int[] res = new int[5];
|
||||
res[NOTIFICATION] = R.drawable.ic_magisk_outline;
|
||||
res[SUPERUSER] = R.drawable.sc_superuser;
|
||||
res[MAGISKHIDE] = R.drawable.sc_magiskhide;
|
||||
res[DOWNLOAD] = R.drawable.sc_cloud_download;
|
||||
res[MODULES] = R.drawable.sc_extension;
|
||||
data.resourceMap = res;
|
||||
}
|
||||
|
||||
static String get(String name) {
|
Loading…
x
Reference in New Issue
Block a user