mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 18:57: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.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
import io.michaelrocks.paranoid.Obfuscate;
|
import io.michaelrocks.paranoid.Obfuscate;
|
||||||
@ -17,12 +20,21 @@ public class DelegateRootService extends ContextWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attachBaseContext(Context base) {
|
protected void attachBaseContext(Context base) {
|
||||||
if (DynLoad.createApp(base) == null)
|
if (!DynLoad.loadApk(base))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create the actual RootService and call its attachBaseContext
|
|
||||||
try {
|
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);
|
ctor.setAccessible(true);
|
||||||
Object service = ctor.newInstance(this);
|
Object service = ctor.newInstance(this);
|
||||||
DynLoad.attachContext(service, base);
|
DynLoad.attachContext(service, base);
|
||||||
|
@ -7,7 +7,6 @@ import android.app.Application;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
@ -31,10 +30,17 @@ public class DynLoad {
|
|||||||
// The current active classloader
|
// The current active classloader
|
||||||
static ClassLoader loader = new RedirectClassLoader();
|
static ClassLoader loader = new RedirectClassLoader();
|
||||||
static Object componentFactory;
|
static Object componentFactory;
|
||||||
static final StubApk.Data apkData = createApkData();
|
|
||||||
|
|
||||||
private static boolean loadedApk = false;
|
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) {
|
static void attachContext(Object o, Context context) {
|
||||||
if (!(o instanceof ContextWrapper))
|
if (!(o instanceof ContextWrapper))
|
||||||
return;
|
return;
|
||||||
@ -95,16 +101,16 @@ public class DynLoad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamically load APK and create the Application instance from the loaded APK
|
// Dynamically load APK from internal, external storage, or previous app
|
||||||
static Application createApp(Context context) {
|
static boolean loadApk(Context context) {
|
||||||
// Trigger folder creation
|
// Trigger folder creation
|
||||||
context.getExternalFilesDir(null);
|
context.getExternalFilesDir(null);
|
||||||
|
|
||||||
File apk = StubApk.current(context);
|
|
||||||
loadApk(context.getApplicationInfo());
|
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 (!isDynLoader() && !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);
|
||||||
@ -120,54 +126,52 @@ public class DynLoad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDynLoader()) {
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stub app setup entry
|
// Dynamically load APK and create the Application instance from the loaded APK
|
||||||
static Application createAndSetupApp(Application context) {
|
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)
|
if (Build.VERSION.SDK_INT < 29)
|
||||||
replaceClassLoader(context);
|
replaceClassLoader(context);
|
||||||
|
|
||||||
Application app = createApp(context);
|
if (!loadApk(context))
|
||||||
if (app != null) {
|
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
|
// Send real application to attachBaseContext
|
||||||
attachContext(app, context);
|
attachContext(app, context);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(DynLoad.class.getSimpleName(), "", e);
|
||||||
|
apk.delete();
|
||||||
}
|
}
|
||||||
return app;
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDynLoader() {
|
private static boolean isDynLoader() {
|
||||||
return loader instanceof InjectedClassLoader;
|
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
|
// Replace LoadedApk mClassLoader
|
||||||
private static void replaceClassLoader(Context context) {
|
private static void replaceClassLoader(Context context) {
|
||||||
// Get ContextImpl
|
// Get ContextImpl
|
||||||
@ -188,12 +192,4 @@ public class DynLoad {
|
|||||||
Log.e(DynLoad.class.getSimpleName(), "", e);
|
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