[core] use dex builder to generate resource dummy class (#215)
This commit is contained in:
parent
27d9fd0a70
commit
cb5c9ea4d2
|
|
@ -1 +1 @@
|
||||||
Subproject commit 360465c7c9f8fe6c81fdae17da6895be0884d9f1
|
Subproject commit 89988a43bd4bdcd2ed38bf7dc5ab2ea01f5e91df
|
||||||
|
|
@ -20,6 +20,9 @@
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <resource_hook.h>
|
#include <resource_hook.h>
|
||||||
|
#include <dex_builder.h>
|
||||||
|
#include <art/runtime/thread.h>
|
||||||
|
#include <art/runtime/mirror/class.h>
|
||||||
#include "native_util.h"
|
#include "native_util.h"
|
||||||
#include "nativehelper/jni_macros.h"
|
#include "nativehelper/jni_macros.h"
|
||||||
#include "resources_hook.h"
|
#include "resources_hook.h"
|
||||||
|
|
@ -43,9 +46,34 @@ namespace lspd {
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent, jobject resource_super_class, jobject typed_array_super_class) {
|
||||||
|
using namespace startop::dex;
|
||||||
|
static auto in_memory_classloader = (jclass)env->NewGlobalRef(env->FindClass( "dalvik/system/InMemoryDexClassLoader"));
|
||||||
|
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
|
||||||
|
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
|
DexBuilder dex_file;
|
||||||
|
|
||||||
|
std::string storage;
|
||||||
|
auto current_thread = art::Thread::Current();
|
||||||
|
ClassBuilder xresource_builder{
|
||||||
|
dex_file.MakeClass("xposed.dummy.XResourcesSuperClass")};
|
||||||
|
xresource_builder.setSuperClass(TypeDescriptor::FromDescriptor(art::mirror::Class(current_thread.DecodeJObject(resource_super_class)).GetDescriptor(&storage)));
|
||||||
|
|
||||||
|
ClassBuilder xtypearray_builder{
|
||||||
|
dex_file.MakeClass("xposed.dummy.XTypedArraySuperClass")};
|
||||||
|
xtypearray_builder.setSuperClass(TypeDescriptor::FromDescriptor(art::mirror::Class(current_thread.DecodeJObject(typed_array_super_class)).GetDescriptor(&storage)));
|
||||||
|
|
||||||
|
slicer::MemView image{dex_file.CreateImage()};
|
||||||
|
|
||||||
|
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void*>(image.ptr()), image.size());
|
||||||
|
return JNI_NewObject(env, in_memory_classloader, initMid,
|
||||||
|
dex_buffer, parent);
|
||||||
|
}
|
||||||
|
|
||||||
static JNINativeMethod gMethods[] = {
|
static JNINativeMethod gMethods[] = {
|
||||||
LSP_NATIVE_METHOD(ResourcesHook, initXResourcesNative, "()Z"),
|
LSP_NATIVE_METHOD(ResourcesHook, initXResourcesNative, "()Z"),
|
||||||
LSP_NATIVE_METHOD(ResourcesHook, removeFinalFlagNative, "(Ljava/lang/Class;)Z"),
|
LSP_NATIVE_METHOD(ResourcesHook, removeFinalFlagNative, "(Ljava/lang/Class;)Z"),
|
||||||
|
LSP_NATIVE_METHOD(ResourcesHook, buildDummyClassLoader, "(Ljava/lang/ClassLoader;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/ClassLoader;"),
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterResourcesHook(JNIEnv *env) {
|
void RegisterResourcesHook(JNIEnv *env) {
|
||||||
|
|
|
||||||
|
|
@ -153,10 +153,8 @@ namespace lspd {
|
||||||
auto *back_method = backup_builder.Encode();
|
auto *back_method = backup_builder.Encode();
|
||||||
|
|
||||||
slicer::MemView image{dex_file.CreateImage()};
|
slicer::MemView image{dex_file.CreateImage()};
|
||||||
std::unique_ptr<char[]> buffer = std::make_unique<char[]>(image.size());
|
|
||||||
memcpy(buffer.get(), image.ptr(), image.size());
|
|
||||||
|
|
||||||
auto dex_buffer = env->NewDirectByteBuffer(buffer.get(), image.size());
|
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void*>(image.ptr()), image.size());
|
||||||
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
|
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
|
||||||
dex_buffer, app_class_loader);
|
dex_buffer, app_class_loader);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||||
import external.com.android.dx.DexMaker;
|
import external.com.android.dx.DexMaker;
|
||||||
import external.com.android.dx.TypeId;
|
import external.com.android.dx.TypeId;
|
||||||
import io.github.lsposed.lspd.nativebridge.ModuleLogger;
|
import io.github.lsposed.lspd.nativebridge.ModuleLogger;
|
||||||
|
import io.github.lsposed.lspd.nativebridge.ResourcesHook;
|
||||||
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
||||||
|
|
||||||
|
|
@ -97,8 +98,8 @@ public final class XposedBridge {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Resources res = Resources.getSystem();
|
Resources res = Resources.getSystem();
|
||||||
Class resClass = res.getClass();
|
Class<?> resClass = res.getClass();
|
||||||
Class taClass = TypedArray.class;
|
Class<?> taClass = TypedArray.class;
|
||||||
try {
|
try {
|
||||||
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
|
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
|
||||||
"preloaded_drawables", "array", "android"));
|
"preloaded_drawables", "array", "android"));
|
||||||
|
|
@ -109,16 +110,20 @@ public final class XposedBridge {
|
||||||
}
|
}
|
||||||
XposedBridge.removeFinalFlagNative(resClass);
|
XposedBridge.removeFinalFlagNative(resClass);
|
||||||
XposedBridge.removeFinalFlagNative(taClass);
|
XposedBridge.removeFinalFlagNative(taClass);
|
||||||
DexMaker dexMaker = new DexMaker();
|
|
||||||
dexMaker.declare(TypeId.get("Lxposed/dummy/XResourcesSuperClass;"),
|
|
||||||
"XResourcesSuperClass.java",
|
|
||||||
Modifier.PUBLIC, TypeId.get(resClass));
|
|
||||||
dexMaker.declare(TypeId.get("Lxposed/dummy/XTypedArraySuperClass;"),
|
|
||||||
"XTypedArraySuperClass.java",
|
|
||||||
Modifier.PUBLIC, TypeId.get(taClass));
|
|
||||||
ClassLoader myCL = XposedBridge.class.getClassLoader();
|
ClassLoader myCL = XposedBridge.class.getClassLoader();
|
||||||
dummyClassLoader = new InMemoryDexClassLoader(
|
dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass);
|
||||||
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
|
if (dummyClassLoader == null) {
|
||||||
|
XposedBridge.log("Dexbuilder fails, fallback to dexmaker");
|
||||||
|
DexMaker dexMaker = new DexMaker();
|
||||||
|
dexMaker.declare(TypeId.get("Lxposed/dummy/XResourcesSuperClass;"),
|
||||||
|
"XResourcesSuperClass.java",
|
||||||
|
Modifier.PUBLIC, TypeId.get(resClass));
|
||||||
|
dexMaker.declare(TypeId.get("Lxposed/dummy/XTypedArraySuperClass;"),
|
||||||
|
"XTypedArraySuperClass.java",
|
||||||
|
Modifier.PUBLIC, TypeId.get(taClass));
|
||||||
|
dummyClassLoader = new InMemoryDexClassLoader(
|
||||||
|
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
|
||||||
|
}
|
||||||
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
|
dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass");
|
||||||
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
|
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
|
||||||
setObjectField(myCL, "parent", dummyClassLoader);
|
setObjectField(myCL, "parent", dummyClassLoader);
|
||||||
|
|
|
||||||
|
|
@ -142,13 +142,12 @@ public final class XposedInit {
|
||||||
final ThreadLocal<Object> latestResKey = new ThreadLocal<>();
|
final ThreadLocal<Object> latestResKey = new ThreadLocal<>();
|
||||||
final String createResourceMethod;
|
final String createResourceMethod;
|
||||||
|
|
||||||
|
classGTLR = android.app.ResourcesManager.class;
|
||||||
|
classResKey = android.content.res.ResourcesKey.class;
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < 30) {
|
if (Build.VERSION.SDK_INT < 30) {
|
||||||
classGTLR = Class.forName("android.app.ResourcesManager");
|
|
||||||
classResKey = Class.forName("android.content.res.ResourcesKey");
|
|
||||||
createResourceMethod = "getOrCreateResources";
|
createResourceMethod = "getOrCreateResources";
|
||||||
} else {
|
} else {
|
||||||
classGTLR = Class.forName("android.app.ResourcesManager");
|
|
||||||
classResKey = Class.forName("android.content.res.ResourcesKey");
|
|
||||||
createResourceMethod = "createResources";
|
createResourceMethod = "createResources";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ public class ResourcesHook {
|
||||||
|
|
||||||
public static native boolean initXResourcesNative();
|
public static native boolean initXResourcesNative();
|
||||||
|
|
||||||
public static native boolean removeFinalFlagNative(Class clazz);
|
public static native boolean removeFinalFlagNative(Class<?> clazz);
|
||||||
|
|
||||||
|
public static native ClassLoader buildDummyClassLoader(ClassLoader parent, Class<?> resourceSuperClass, Class<?> typedArraySuperClass);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package android.app;
|
||||||
|
|
||||||
|
public class ResourcesManager {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package android.content.res;
|
||||||
|
|
||||||
|
public class ResourcesKey {
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue