mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 12:17:38 +00:00
Code refactoring
This commit is contained in:
parent
c09b4dabc4
commit
b7fc15d399
@ -1,33 +1,124 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
import android.app.job.JobService;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.ServiceInfo;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.dummy.DummyProvider;
|
||||||
|
import com.topjohnwu.magisk.dummy.DummyReceiver;
|
||||||
|
import com.topjohnwu.magisk.dummy.DummyService;
|
||||||
import com.topjohnwu.magisk.utils.DynamicClassLoader;
|
import com.topjohnwu.magisk.utils.DynamicClassLoader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.michaelrocks.paranoid.Obfuscate;
|
||||||
|
|
||||||
// Wrap the actual classloader as we only want to resolve classname
|
// Wrap the actual classloader as we only want to resolve classname
|
||||||
// mapping when loading from platform (via LoadedApk.mClassLoader)
|
// mapping when loading from platform (via LoadedApk.mClassLoader)
|
||||||
class InjectedClassLoader extends ClassLoader {
|
@Obfuscate
|
||||||
|
class AppClassLoader extends ClassLoader {
|
||||||
|
|
||||||
InjectedClassLoader(File apk) {
|
final Map<String, String> mapping = new HashMap<>();
|
||||||
|
|
||||||
|
AppClassLoader(File apk) {
|
||||||
super(new DynamicClassLoader(apk));
|
super(new DynamicClassLoader(apk));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
String clz = DynLoad.componentMap.get(name);
|
String clz = mapping.get(name);
|
||||||
name = clz != null ? clz : name;
|
name = clz != null ? clz : name;
|
||||||
return super.loadClass(name, resolve);
|
return super.loadClass(name, resolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateComponentMap(PackageInfo stub, PackageInfo app) {
|
||||||
|
{
|
||||||
|
var src = stub.activities;
|
||||||
|
var dest = app.activities;
|
||||||
|
|
||||||
|
final ActivityInfo sa;
|
||||||
|
final ActivityInfo da;
|
||||||
|
final ActivityInfo sb;
|
||||||
|
final ActivityInfo db;
|
||||||
|
if (src[0].exported) {
|
||||||
|
sa = src[0];
|
||||||
|
sb = src[1];
|
||||||
|
} else {
|
||||||
|
sa = src[1];
|
||||||
|
sb = src[0];
|
||||||
|
}
|
||||||
|
if (dest[0].exported) {
|
||||||
|
da = dest[0];
|
||||||
|
db = dest[1];
|
||||||
|
} else {
|
||||||
|
da = dest[1];
|
||||||
|
db = dest[0];
|
||||||
|
}
|
||||||
|
mapping.put(sa.name, da.name);
|
||||||
|
mapping.put(sb.name, db.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var src = stub.services;
|
||||||
|
var dest = app.services;
|
||||||
|
|
||||||
|
final ServiceInfo sa;
|
||||||
|
final ServiceInfo da;
|
||||||
|
final ServiceInfo sb;
|
||||||
|
final ServiceInfo db;
|
||||||
|
if (JobService.PERMISSION_BIND.equals(src[0].permission)) {
|
||||||
|
sa = src[0];
|
||||||
|
sb = src[1];
|
||||||
|
} else {
|
||||||
|
sa = src[1];
|
||||||
|
sb = src[0];
|
||||||
|
}
|
||||||
|
if (JobService.PERMISSION_BIND.equals(dest[0].permission)) {
|
||||||
|
da = dest[0];
|
||||||
|
db = dest[1];
|
||||||
|
} else {
|
||||||
|
da = dest[1];
|
||||||
|
db = dest[0];
|
||||||
|
}
|
||||||
|
mapping.put(sa.name, da.name);
|
||||||
|
mapping.put(sb.name, db.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var src = stub.receivers;
|
||||||
|
var dest = app.receivers;
|
||||||
|
mapping.put(src[0].name, dest[0].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var src = stub.providers;
|
||||||
|
var dest = app.providers;
|
||||||
|
mapping.put(src[0].name, dest[0].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RedirectClassLoader extends ClassLoader {
|
class StubClassLoader extends ClassLoader {
|
||||||
|
|
||||||
private final Map<String, Class<?>> mapping;
|
private final Map<String, Class<?>> mapping = new HashMap<>();
|
||||||
|
|
||||||
RedirectClassLoader(Map<String, Class<?>> m) {
|
StubClassLoader(PackageInfo info) {
|
||||||
super(RedirectClassLoader.class.getClassLoader());
|
super(StubClassLoader.class.getClassLoader());
|
||||||
mapping = m;
|
for (var c : info.activities) {
|
||||||
|
mapping.put(c.name, DownloadActivity.class);
|
||||||
|
}
|
||||||
|
for (var c : info.services) {
|
||||||
|
mapping.put(c.name, DummyService.class);
|
||||||
|
}
|
||||||
|
for (var c : info.providers) {
|
||||||
|
mapping.put(c.name, DummyProvider.class);
|
||||||
|
}
|
||||||
|
for (var c : info.receivers) {
|
||||||
|
mapping.put(c.name, DummyReceiver.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -39,12 +130,15 @@ class RedirectClassLoader extends ClassLoader {
|
|||||||
|
|
||||||
class DelegateClassLoader extends ClassLoader {
|
class DelegateClassLoader extends ClassLoader {
|
||||||
|
|
||||||
|
// The active classloader
|
||||||
|
static ClassLoader cl = DelegateClassLoader.class.getClassLoader();
|
||||||
|
|
||||||
DelegateClassLoader() {
|
DelegateClassLoader() {
|
||||||
super(null);
|
super(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
return DynLoad.loader.loadClass(name);
|
return cl.loadClass(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.os.Process;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.dummy.DummyProvider;
|
import com.topjohnwu.magisk.dummy.DummyProvider;
|
||||||
import com.topjohnwu.magisk.dummy.DummyReceiver;
|
import com.topjohnwu.magisk.dummy.DummyReceiver;
|
||||||
@ -26,11 +25,6 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo info) {
|
public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo info) {
|
||||||
if (Process.myUid() == 0) {
|
|
||||||
// Do not do anything in root process
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
DynLoad.loadApk(info);
|
|
||||||
return new DelegateClassLoader();
|
return new DelegateClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +37,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
public Activity instantiateActivity(ClassLoader cl, String className, Intent intent)
|
public Activity instantiateActivity(ClassLoader cl, String className, Intent intent)
|
||||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||||
if (receiver != null)
|
if (receiver != null)
|
||||||
return receiver.instantiateActivity(DynLoad.loader, className, intent);
|
return receiver.instantiateActivity(DelegateClassLoader.cl, className, intent);
|
||||||
return create(className, DownloadActivity.class);
|
return create(className, DownloadActivity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +45,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent)
|
public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent)
|
||||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||||
if (receiver != null)
|
if (receiver != null)
|
||||||
return receiver.instantiateReceiver(DynLoad.loader, className, intent);
|
return receiver.instantiateReceiver(DelegateClassLoader.cl, className, intent);
|
||||||
return create(className, DummyReceiver.class);
|
return create(className, DummyReceiver.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +53,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
public Service instantiateService(ClassLoader cl, String className, Intent intent)
|
public Service instantiateService(ClassLoader cl, String className, Intent intent)
|
||||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||||
if (receiver != null)
|
if (receiver != null)
|
||||||
return receiver.instantiateService(DynLoad.loader, className, intent);
|
return receiver.instantiateService(DelegateClassLoader.cl, className, intent);
|
||||||
return create(className, DummyService.class);
|
return create(className, DummyService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +61,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
public ContentProvider instantiateProvider(ClassLoader cl, String className)
|
public ContentProvider instantiateProvider(ClassLoader cl, String className)
|
||||||
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||||
if (receiver != null)
|
if (receiver != null)
|
||||||
return receiver.instantiateProvider(DynLoad.loader, className);
|
return receiver.instantiateProvider(DelegateClassLoader.cl, className);
|
||||||
return create(className, DummyProvider.class);
|
return create(className, DummyProvider.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +69,7 @@ public class DelegateComponentFactory extends AppComponentFactory {
|
|||||||
throws IllegalAccessException, InstantiationException {
|
throws IllegalAccessException, InstantiationException {
|
||||||
try {
|
try {
|
||||||
// noinspection unchecked
|
// noinspection unchecked
|
||||||
return (T) DynLoad.loader.loadClass(name).newInstance();
|
return (T) DelegateClassLoader.cl.loadClass(name).newInstance();
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
return fallback.newInstance();
|
return fallback.newInstance();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ public class DelegateRootService extends ContextWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attachBaseContext(Context base) {
|
protected void attachBaseContext(Context base) {
|
||||||
if (!DynLoad.loadApk(base))
|
ClassLoader loader = DynLoad.loadApk(base);
|
||||||
|
if (loader == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -29,7 +30,7 @@ public class DelegateRootService extends ContextWrapper {
|
|||||||
File apk = StubApk.current(base);
|
File apk = StubApk.current(base);
|
||||||
PackageManager pm = base.getPackageManager();
|
PackageManager pm = base.getPackageManager();
|
||||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apk.getPath(), 0);
|
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apk.getPath(), 0);
|
||||||
DynLoad.loader.loadClass(pkgInfo.applicationInfo.className)
|
loader.loadClass(pkgInfo.applicationInfo.className)
|
||||||
.getConstructor(Object.class)
|
.getConstructor(Object.class)
|
||||||
.newInstance(data.getObject());
|
.newInstance(data.getObject());
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class DownloadActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (DynLoad.isDynLoader()) {
|
if (DelegateClassLoader.cl instanceof AppClassLoader) {
|
||||||
// For some reason activity is created before Application.attach(),
|
// For some reason activity is created before Application.attach(),
|
||||||
// relaunch the activity using the same intent
|
// relaunch the activity using the same intent
|
||||||
finishAffinity();
|
finishAffinity();
|
||||||
|
@ -4,21 +4,13 @@ import static com.topjohnwu.magisk.BuildConfig.APPLICATION_ID;
|
|||||||
|
|
||||||
import android.app.AppComponentFactory;
|
import android.app.AppComponentFactory;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.job.JobService;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.pm.ActivityInfo;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.dummy.DummyProvider;
|
|
||||||
import com.topjohnwu.magisk.dummy.DummyReceiver;
|
|
||||||
import com.topjohnwu.magisk.dummy.DummyService;
|
|
||||||
import com.topjohnwu.magisk.utils.APKInstall;
|
import com.topjohnwu.magisk.utils.APKInstall;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -28,7 +20,6 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import io.michaelrocks.paranoid.Obfuscate;
|
import io.michaelrocks.paranoid.Obfuscate;
|
||||||
|
|
||||||
@ -36,21 +27,12 @@ import io.michaelrocks.paranoid.Obfuscate;
|
|||||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
public class DynLoad {
|
public class DynLoad {
|
||||||
|
|
||||||
// The current active classloader
|
|
||||||
static ClassLoader loader = DynLoad.class.getClassLoader();
|
|
||||||
static Object componentFactory;
|
static Object componentFactory;
|
||||||
static Map<String, String> componentMap = new HashMap<>();
|
|
||||||
|
|
||||||
private static boolean loadedApk = false;
|
|
||||||
|
|
||||||
static StubApk.Data createApkData() {
|
static StubApk.Data createApkData() {
|
||||||
var data = new StubApk.Data();
|
var data = new StubApk.Data();
|
||||||
data.setVersion(BuildConfig.STUB_VERSION);
|
data.setVersion(BuildConfig.STUB_VERSION);
|
||||||
Map<String, String> map = new HashMap<>();
|
data.setClassToComponent(new HashMap<>());
|
||||||
for (var e : componentMap.entrySet()) {
|
|
||||||
map.put(e.getValue(), e.getKey());
|
|
||||||
}
|
|
||||||
data.setClassToComponent(map);
|
|
||||||
data.setRootService(DelegateRootService.class);
|
data.setRootService(DelegateRootService.class);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -65,14 +47,10 @@ public class DynLoad {
|
|||||||
} catch (Exception ignored) { /* Impossible */ }
|
} catch (Exception ignored) { /* Impossible */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamically load APK from internal or external storage
|
// Dynamically load APK from internal, external storage, or previous app
|
||||||
static void loadApk(ApplicationInfo info) {
|
static AppClassLoader loadApk(Context context) {
|
||||||
if (loadedApk)
|
File apk = StubApk.current(context);
|
||||||
return;
|
File update = StubApk.update(context);
|
||||||
loadedApk = true;
|
|
||||||
|
|
||||||
File apk = StubApk.current(info);
|
|
||||||
File update = StubApk.update(info);
|
|
||||||
|
|
||||||
if (update.exists()) {
|
if (update.exists()) {
|
||||||
// Rename from update
|
// Rename from update
|
||||||
@ -80,20 +58,8 @@ public class DynLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy from external for easier development
|
// Copy from external for easier development
|
||||||
if (BuildConfig.DEBUG) copy_from_ext: {
|
if (BuildConfig.DEBUG) {
|
||||||
final File dir;
|
File external = new File(context.getExternalFilesDir(null), "magisk.apk");
|
||||||
try {
|
|
||||||
var dirs = (File[]) Environment.class
|
|
||||||
.getMethod("buildExternalStorageAppFilesDirs", String.class)
|
|
||||||
.invoke(null, info.packageName);
|
|
||||||
if (dirs == null)
|
|
||||||
break copy_from_ext;
|
|
||||||
dir = dirs[0];
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
|
||||||
break copy_from_ext;
|
|
||||||
}
|
|
||||||
File external = new File(dir, "magisk.apk");
|
|
||||||
if (external.exists()) {
|
if (external.exists()) {
|
||||||
try {
|
try {
|
||||||
var in = new FileInputStream(external);
|
var in = new FileInputStream(external);
|
||||||
@ -111,20 +77,11 @@ public class DynLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (apk.exists()) {
|
if (apk.exists()) {
|
||||||
loader = new InjectedClassLoader(apk);
|
return new AppClassLoader(apk);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamically load APK from internal, external storage, or previous app
|
|
||||||
static boolean loadApk(Context context) {
|
|
||||||
// Trigger folder creation
|
|
||||||
context.getExternalFilesDir(null);
|
|
||||||
|
|
||||||
loadApk(context.getApplicationInfo());
|
|
||||||
|
|
||||||
// If no APK is loaded, attempt to copy from previous app
|
// If no APK is loaded, attempt to copy from previous app
|
||||||
if (!isDynLoader() && !context.getPackageName().equals(APPLICATION_ID)) {
|
if (!context.getPackageName().equals(APPLICATION_ID)) {
|
||||||
File apk = StubApk.current(context);
|
|
||||||
try {
|
try {
|
||||||
var info = context.getPackageManager().getApplicationInfo(APPLICATION_ID, 0);
|
var info = context.getPackageManager().getApplicationInfo(APPLICATION_ID, 0);
|
||||||
var src = new FileInputStream(info.sourceDir);
|
var src = new FileInputStream(info.sourceDir);
|
||||||
@ -132,7 +89,7 @@ public class DynLoad {
|
|||||||
try (src; out) {
|
try (src; out) {
|
||||||
APKInstall.transfer(src, out);
|
APKInstall.transfer(src, out);
|
||||||
}
|
}
|
||||||
loader = new InjectedClassLoader(apk);
|
return new AppClassLoader(apk);
|
||||||
} catch (PackageManager.NameNotFoundException ignored) {
|
} catch (PackageManager.NameNotFoundException ignored) {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
Log.e(DynLoad.class.getSimpleName(), "", e);
|
||||||
@ -140,7 +97,7 @@ public class DynLoad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return isDynLoader();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamically load APK and create the Application instance from the loaded APK
|
// Dynamically load APK and create the Application instance from the loaded APK
|
||||||
@ -161,32 +118,37 @@ public class DynLoad {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loadApk(context)) {
|
|
||||||
loader = new RedirectClassLoader(createInternalMap(info));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
File apk = StubApk.current(context);
|
File apk = StubApk.current(context);
|
||||||
PackageManager pm = context.getPackageManager();
|
|
||||||
try {
|
final var cl = loadApk(context);
|
||||||
var pkgInfo = pm.getPackageArchiveInfo(apk.getPath(), flags);
|
if (cl != null) try {
|
||||||
|
var pkgInfo = context.getPackageManager()
|
||||||
|
.getPackageArchiveInfo(apk.getPath(), flags);
|
||||||
|
cl.updateComponentMap(info, pkgInfo);
|
||||||
|
|
||||||
var appInfo = pkgInfo.applicationInfo;
|
var appInfo = pkgInfo.applicationInfo;
|
||||||
|
|
||||||
updateComponentMap(info, pkgInfo);
|
var data = createApkData();
|
||||||
|
var map = data.getClassToComponent();
|
||||||
|
// Create the inverse mapping (class to component name)
|
||||||
|
for (var e : cl.mapping.entrySet()) {
|
||||||
|
map.put(e.getValue(), e.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
// Create the receiver Application
|
// Create the receiver Application
|
||||||
var data = createApkData();
|
var app = (Application) cl.loadClass(appInfo.className)
|
||||||
var app = (Application) loader.loadClass(appInfo.className)
|
|
||||||
.getConstructor(Object.class)
|
.getConstructor(Object.class)
|
||||||
.newInstance(data.getObject());
|
.newInstance(data.getObject());
|
||||||
|
|
||||||
// Create the receiver component factory
|
// Create the receiver component factory
|
||||||
if (Build.VERSION.SDK_INT >= 28 && componentFactory != null) {
|
if (Build.VERSION.SDK_INT >= 28 && componentFactory != null) {
|
||||||
Object factory = loader.loadClass(appInfo.appComponentFactory).newInstance();
|
Object factory = cl.loadClass(appInfo.appComponentFactory).newInstance();
|
||||||
var delegate = (DelegateComponentFactory) componentFactory;
|
var delegate = (DelegateComponentFactory) componentFactory;
|
||||||
delegate.receiver = (AppComponentFactory) factory;
|
delegate.receiver = (AppComponentFactory) factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DelegateClassLoader.cl = cl;
|
||||||
|
|
||||||
// Send real application to attachBaseContext
|
// Send real application to attachBaseContext
|
||||||
attachContext(app, context);
|
attachContext(app, context);
|
||||||
|
|
||||||
@ -196,97 +158,12 @@ public class DynLoad {
|
|||||||
apk.delete();
|
apk.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DelegateClassLoader.cl = new StubClassLoader(info);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Class<?>> createInternalMap(PackageInfo info) {
|
|
||||||
Map<String, Class<?>> map = new HashMap<>();
|
|
||||||
for (var c : info.activities) {
|
|
||||||
map.put(c.name, DownloadActivity.class);
|
|
||||||
}
|
|
||||||
for (var c : info.services) {
|
|
||||||
map.put(c.name, DummyService.class);
|
|
||||||
}
|
|
||||||
for (var c : info.providers) {
|
|
||||||
map.put(c.name, DummyProvider.class);
|
|
||||||
}
|
|
||||||
for (var c : info.receivers) {
|
|
||||||
map.put(c.name, DummyReceiver.class);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateComponentMap(PackageInfo from, PackageInfo to) {
|
|
||||||
{
|
|
||||||
var src = from.activities;
|
|
||||||
var dest = to.activities;
|
|
||||||
|
|
||||||
final ActivityInfo sa;
|
|
||||||
final ActivityInfo da;
|
|
||||||
final ActivityInfo sb;
|
|
||||||
final ActivityInfo db;
|
|
||||||
if (src[0].exported) {
|
|
||||||
sa = src[0];
|
|
||||||
sb = src[1];
|
|
||||||
} else {
|
|
||||||
sa = src[1];
|
|
||||||
sb = src[0];
|
|
||||||
}
|
|
||||||
if (dest[0].exported) {
|
|
||||||
da = dest[0];
|
|
||||||
db = dest[1];
|
|
||||||
} else {
|
|
||||||
da = dest[1];
|
|
||||||
db = dest[0];
|
|
||||||
}
|
|
||||||
componentMap.put(sa.name, da.name);
|
|
||||||
componentMap.put(sb.name, db.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var src = from.services;
|
|
||||||
var dest = to.services;
|
|
||||||
|
|
||||||
final ServiceInfo sa;
|
|
||||||
final ServiceInfo da;
|
|
||||||
final ServiceInfo sb;
|
|
||||||
final ServiceInfo db;
|
|
||||||
if (JobService.PERMISSION_BIND.equals(src[0].permission)) {
|
|
||||||
sa = src[0];
|
|
||||||
sb = src[1];
|
|
||||||
} else {
|
|
||||||
sa = src[1];
|
|
||||||
sb = src[0];
|
|
||||||
}
|
|
||||||
if (JobService.PERMISSION_BIND.equals(dest[0].permission)) {
|
|
||||||
da = dest[0];
|
|
||||||
db = dest[1];
|
|
||||||
} else {
|
|
||||||
da = dest[1];
|
|
||||||
db = dest[0];
|
|
||||||
}
|
|
||||||
componentMap.put(sa.name, da.name);
|
|
||||||
componentMap.put(sb.name, db.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var src = from.receivers;
|
|
||||||
var dest = to.receivers;
|
|
||||||
componentMap.put(src[0].name, dest[0].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
var src = from.providers;
|
|
||||||
var dest = to.providers;
|
|
||||||
componentMap.put(src[0].name, dest[0].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isDynLoader() {
|
|
||||||
return loader instanceof InjectedClassLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace LoadedApk mClassLoader
|
// Replace LoadedApk mClassLoader
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
private static void replaceClassLoader(Context context) {
|
private static void replaceClassLoader(Context context) {
|
||||||
// Get ContextImpl
|
// Get ContextImpl
|
||||||
while (context instanceof ContextWrapper) {
|
while (context instanceof ContextWrapper) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user