mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 03:47:37 +00:00
Refactor DynLoad
This commit is contained in:
parent
8f0ea5925a
commit
a4aa4a91a3
@ -2,8 +2,11 @@ package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import io.michaelrocks.paranoid.Obfuscate;
|
||||
@ -17,12 +20,21 @@ public class DelegateRootService extends ContextWrapper {
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
if (DynLoad.createApp(base) == null)
|
||||
if (!DynLoad.loadApk(base))
|
||||
return;
|
||||
|
||||
// Create the actual RootService and call its attachBaseContext
|
||||
try {
|
||||
Constructor<?> ctor = DynLoad.apkData.getRootService().getConstructor(Object.class);
|
||||
// Create application to get the real root service class
|
||||
var data = DynLoad.createApkData();
|
||||
File apk = StubApk.current(base);
|
||||
PackageManager pm = base.getPackageManager();
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apk.getPath(), 0);
|
||||
DynLoad.loader.loadClass(pkgInfo.applicationInfo.className)
|
||||
.getConstructor(Object.class)
|
||||
.newInstance(data.getObject());
|
||||
|
||||
// Create the actual RootService and call its attachBaseContext
|
||||
Constructor<?> ctor = data.getRootService().getConstructor(Object.class);
|
||||
ctor.setAccessible(true);
|
||||
Object service = ctor.newInstance(this);
|
||||
DynLoad.attachContext(service, base);
|
||||
|
@ -7,7 +7,6 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
@ -31,10 +30,17 @@ public class DynLoad {
|
||||
// The current active classloader
|
||||
static ClassLoader loader = new RedirectClassLoader();
|
||||
static Object componentFactory;
|
||||
static final StubApk.Data apkData = createApkData();
|
||||
|
||||
private static boolean loadedApk = false;
|
||||
|
||||
static StubApk.Data createApkData() {
|
||||
var data = new StubApk.Data();
|
||||
data.setVersion(BuildConfig.STUB_VERSION);
|
||||
data.setClassToComponent(Mapping.inverseMap);
|
||||
data.setRootService(DelegateRootService.class);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void attachContext(Object o, Context context) {
|
||||
if (!(o instanceof ContextWrapper))
|
||||
return;
|
||||
@ -95,16 +101,16 @@ public class DynLoad {
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamically load APK and create the Application instance from the loaded APK
|
||||
static Application createApp(Context context) {
|
||||
// Dynamically load APK from internal, external storage, or previous app
|
||||
static boolean loadApk(Context context) {
|
||||
// Trigger folder creation
|
||||
context.getExternalFilesDir(null);
|
||||
|
||||
File apk = StubApk.current(context);
|
||||
loadApk(context.getApplicationInfo());
|
||||
|
||||
// If no APK is loaded, attempt to copy from previous app
|
||||
if (!isDynLoader() && !context.getPackageName().equals(APPLICATION_ID)) {
|
||||
File apk = StubApk.current(context);
|
||||
try {
|
||||
var info = context.getPackageManager().getApplicationInfo(APPLICATION_ID, 0);
|
||||
var src = new FileInputStream(info.sourceDir);
|
||||
@ -120,54 +126,52 @@ public class DynLoad {
|
||||
}
|
||||
}
|
||||
|
||||
if (isDynLoader()) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(apk.getPath(), 0);
|
||||
try {
|
||||
return newApp(pkgInfo.applicationInfo);
|
||||
} catch (ReflectiveOperationException | NullPointerException e) {
|
||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
||||
apk.delete();
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
return isDynLoader();
|
||||
}
|
||||
|
||||
// Stub app setup entry
|
||||
// Dynamically load APK and create the Application instance from the loaded APK
|
||||
static Application createAndSetupApp(Application context) {
|
||||
// On API >= 29, AppComponentFactory will replace the ClassLoader
|
||||
// On API >= 29, AppComponentFactory will replace the ClassLoader for us
|
||||
if (Build.VERSION.SDK_INT < 29)
|
||||
replaceClassLoader(context);
|
||||
|
||||
Application app = createApp(context);
|
||||
if (app != null) {
|
||||
if (!loadApk(context))
|
||||
return null;
|
||||
|
||||
File apk = StubApk.current(context);
|
||||
PackageManager pm = context.getPackageManager();
|
||||
try {
|
||||
var info = pm.getPackageArchiveInfo(apk.getPath(), 0).applicationInfo;
|
||||
|
||||
// Create the receiver Application
|
||||
var data = createApkData();
|
||||
var app = (Application) loader.loadClass(info.className)
|
||||
.getConstructor(Object.class)
|
||||
.newInstance(data.getObject());
|
||||
|
||||
// Create the receiver component factory
|
||||
if (Build.VERSION.SDK_INT >= 28 && componentFactory != null) {
|
||||
Object factory = loader.loadClass(info.appComponentFactory).newInstance();
|
||||
var delegate = (DelegateComponentFactory) componentFactory;
|
||||
delegate.receiver = (AppComponentFactory) factory;
|
||||
}
|
||||
|
||||
// Send real application to attachBaseContext
|
||||
attachContext(app, context);
|
||||
|
||||
return app;
|
||||
} catch (Exception e) {
|
||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
||||
apk.delete();
|
||||
}
|
||||
return app;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isDynLoader() {
|
||||
return loader instanceof InjectedClassLoader;
|
||||
}
|
||||
|
||||
private static Application newApp(ApplicationInfo info) throws ReflectiveOperationException {
|
||||
// Create the receiver Application
|
||||
var app = (Application) loader.loadClass(info.className)
|
||||
.getConstructor(Object.class)
|
||||
.newInstance(apkData.getObject());
|
||||
|
||||
// Create the receiver component factory
|
||||
if (Build.VERSION.SDK_INT >= 28 && componentFactory != null) {
|
||||
Object factory = loader.loadClass(info.appComponentFactory).newInstance();
|
||||
var delegate = (DelegateComponentFactory) componentFactory;
|
||||
delegate.receiver = (AppComponentFactory) factory;
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
// Replace LoadedApk mClassLoader
|
||||
private static void replaceClassLoader(Context context) {
|
||||
// Get ContextImpl
|
||||
@ -188,12 +192,4 @@ public class DynLoad {
|
||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static StubApk.Data createApkData() {
|
||||
var data = new StubApk.Data();
|
||||
data.setVersion(BuildConfig.STUB_VERSION);
|
||||
data.setClassToComponent(Mapping.inverseMap);
|
||||
data.setRootService(DelegateRootService.class);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user