Magisk/stub/src/main/java/com/topjohnwu/magisk/ClassLoaders.java

138 lines
3.9 KiB
Java

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 java.io.File;
import java.util.HashMap;
import java.util.Map;
// Wrap the actual classloader as we only want to resolve classname
// mapping when loading from platform (via LoadedApk.mClassLoader)
class AppClassLoader extends ClassLoader {
final Map<String, String> mapping = new HashMap<>();
AppClassLoader(File apk) {
super(new DynamicClassLoader(apk));
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
String clz = mapping.get(name);
name = clz != null ? clz : name;
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 StubClassLoader extends ClassLoader {
private final Map<String, Class<?>> mapping = new HashMap<>();
StubClassLoader(PackageInfo info) {
super(StubClassLoader.class.getClassLoader());
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
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> clz = mapping.get(name);
return clz == null ? super.loadClass(name, resolve) : clz;
}
}
class DelegateClassLoader extends ClassLoader {
DelegateClassLoader() {
super();
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return DynLoad.activeClassLoader.loadClass(name);
}
}