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:
topjohnwu
2019-10-17 02:04:22 -04:00
parent 9f9de8c43b
commit 40eda05a30
16 changed files with 161 additions and 133 deletions
@@ -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();
}
}
}
}