diff --git a/core/src/main/cpp/external/DexBuilder b/core/src/main/cpp/external/DexBuilder index 360465c7..89988a43 160000 --- a/core/src/main/cpp/external/DexBuilder +++ b/core/src/main/cpp/external/DexBuilder @@ -1 +1 @@ -Subproject commit 360465c7c9f8fe6c81fdae17da6895be0884d9f1 +Subproject commit 89988a43bd4bdcd2ed38bf7dc5ab2ea01f5e91df diff --git a/core/src/main/cpp/main/src/jni/resources_hook.cpp b/core/src/main/cpp/main/src/jni/resources_hook.cpp index d4053de6..2d48a25a 100644 --- a/core/src/main/cpp/main/src/jni/resources_hook.cpp +++ b/core/src/main/cpp/main/src/jni/resources_hook.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include +#include #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, "", + "(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(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) { diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index 2d597683..23b88a50 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -153,10 +153,8 @@ namespace lspd { auto *back_method = backup_builder.Encode(); slicer::MemView image{dex_file.CreateImage()}; - std::unique_ptr buffer = std::make_unique(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(image.ptr()), image.size()); jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid, dex_buffer, app_class_loader); diff --git a/core/src/main/java/de/robv/android/xposed/XposedBridge.java b/core/src/main/java/de/robv/android/xposed/XposedBridge.java index aa1af28f..0b9479b6 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -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); diff --git a/core/src/main/java/de/robv/android/xposed/XposedInit.java b/core/src/main/java/de/robv/android/xposed/XposedInit.java index e51e1497..eb9b8945 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/core/src/main/java/de/robv/android/xposed/XposedInit.java @@ -142,13 +142,12 @@ public final class XposedInit { final ThreadLocal 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"; } diff --git a/core/src/main/java/io/github/lsposed/lspd/nativebridge/ResourcesHook.java b/core/src/main/java/io/github/lsposed/lspd/nativebridge/ResourcesHook.java index d4ef9089..1d38bd75 100644 --- a/core/src/main/java/io/github/lsposed/lspd/nativebridge/ResourcesHook.java +++ b/core/src/main/java/io/github/lsposed/lspd/nativebridge/ResourcesHook.java @@ -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); } diff --git a/hiddenapi-stubs/src/main/java/android/app/ResourcesManager.java b/hiddenapi-stubs/src/main/java/android/app/ResourcesManager.java new file mode 100644 index 00000000..3132dff5 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/app/ResourcesManager.java @@ -0,0 +1,4 @@ +package android.app; + +public class ResourcesManager { +} diff --git a/hiddenapi-stubs/src/main/java/android/content/res/ResourcesKey.java b/hiddenapi-stubs/src/main/java/android/content/res/ResourcesKey.java new file mode 100644 index 00000000..f82c90a3 --- /dev/null +++ b/hiddenapi-stubs/src/main/java/android/content/res/ResourcesKey.java @@ -0,0 +1,4 @@ +package android.content.res; + +public class ResourcesKey { +}