[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 <resource_hook.h>
|
||||
#include <dex_builder.h>
|
||||
#include <art/runtime/thread.h>
|
||||
#include <art/runtime/mirror/class.h>
|
||||
#include "native_util.h"
|
||||
#include "nativehelper/jni_macros.h"
|
||||
#include "resources_hook.h"
|
||||
|
|
@ -43,9 +46,34 @@ namespace lspd {
|
|||
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[] = {
|
||||
LSP_NATIVE_METHOD(ResourcesHook, initXResourcesNative, "()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) {
|
||||
|
|
|
|||
|
|
@ -153,10 +153,8 @@ namespace lspd {
|
|||
auto *back_method = backup_builder.Encode();
|
||||
|
||||
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,
|
||||
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.TypeId;
|
||||
import io.github.lsposed.lspd.nativebridge.ModuleLogger;
|
||||
import io.github.lsposed.lspd.nativebridge.ResourcesHook;
|
||||
|
||||
import static de.robv.android.xposed.XposedHelpers.setObjectField;
|
||||
|
||||
|
|
@ -97,8 +98,8 @@ public final class XposedBridge {
|
|||
}
|
||||
try {
|
||||
Resources res = Resources.getSystem();
|
||||
Class resClass = res.getClass();
|
||||
Class taClass = TypedArray.class;
|
||||
Class<?> resClass = res.getClass();
|
||||
Class<?> taClass = TypedArray.class;
|
||||
try {
|
||||
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
|
||||
"preloaded_drawables", "array", "android"));
|
||||
|
|
@ -109,16 +110,20 @@ public final class XposedBridge {
|
|||
}
|
||||
XposedBridge.removeFinalFlagNative(resClass);
|
||||
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();
|
||||
dummyClassLoader = new InMemoryDexClassLoader(
|
||||
ByteBuffer.wrap(dexMaker.generate()), myCL.getParent());
|
||||
dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass, taClass);
|
||||
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.XTypedArraySuperClass");
|
||||
setObjectField(myCL, "parent", dummyClassLoader);
|
||||
|
|
|
|||
|
|
@ -142,13 +142,12 @@ public final class XposedInit {
|
|||
final ThreadLocal<Object> latestResKey = new ThreadLocal<>();
|
||||
final String createResourceMethod;
|
||||
|
||||
classGTLR = android.app.ResourcesManager.class;
|
||||
classResKey = android.content.res.ResourcesKey.class;
|
||||
|
||||
if (Build.VERSION.SDK_INT < 30) {
|
||||
classGTLR = Class.forName("android.app.ResourcesManager");
|
||||
classResKey = Class.forName("android.content.res.ResourcesKey");
|
||||
createResourceMethod = "getOrCreateResources";
|
||||
} else {
|
||||
classGTLR = Class.forName("android.app.ResourcesManager");
|
||||
classResKey = Class.forName("android.content.res.ResourcesKey");
|
||||
createResourceMethod = "createResources";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public class ResourcesHook {
|
|||
|
||||
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