From 2388517b96b189475c631fb500506418d09f75cf Mon Sep 17 00:00:00 2001 From: LoveSy Date: Thu, 14 Oct 2021 19:45:32 +0800 Subject: [PATCH] [core] Fix resource hook in Android 12 (#1270) --- .../de/robv/android/xposed/XposedInit.java | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) 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 7d3ef591..7f4bbe4f 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/core/src/main/java/de/robv/android/xposed/XposedInit.java @@ -53,6 +53,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -101,46 +102,70 @@ public final class XposedInit { final Class classGTLR; final Class classResKey; final ThreadLocal latestResKey = new ThreadLocal<>(); - final String createResourceMethod; + final ArrayList createResourceMethods = new ArrayList<>(); classGTLR = android.app.ResourcesManager.class; classResKey = android.content.res.ResourcesKey.class; - - if (Build.VERSION.SDK_INT < 30) { - createResourceMethod = "getOrCreateResources"; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + createResourceMethods.add("createResources"); + createResourceMethods.add("createResourcesForActivity"); + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + createResourceMethods.add("createResources"); } else { - createResourceMethod = "createResources"; + createResourceMethods.add("getOrCreateResources"); } - hookAllMethods(classGTLR, createResourceMethod, new XC_MethodHook() { + //noinspection TrivialFunctionalExpressionUsage + final Class classActivityRes = ((Callable>) () -> { + try { + return XposedHelpers.findClass("android.app.ResourcesManager$ActivityResource", classGTLR.getClassLoader()); + } catch (Throwable ignored) { + return null; + } + }).call(); + + + var hooker = new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { // At least on OnePlus 5, the method has an additional parameter compared to AOSP. - final int activityTokenIdx = getParameterIndexByType(param.method, IBinder.class); + Object activityToken = null; + try { + final int activityTokenIdx = getParameterIndexByType(param.method, IBinder.class); + activityToken = param.args[activityTokenIdx]; + } catch (NoSuchFieldError ignored) { + } final int resKeyIdx = getParameterIndexByType(param.method, classResKey); - String resDir = (String) getObjectField(param.args[resKeyIdx], "mResDir"); XResources newRes = cloneToXResources(param, resDir); if (newRes == null) { return; } - Object activityToken = param.args[activityTokenIdx]; //noinspection SynchronizeOnNonFinalField synchronized (param.thisObject) { - ArrayList> resourceReferences; + ArrayList resourceReferences; if (activityToken != null) { Object activityResources = callMethod(param.thisObject, "getOrCreateActivityResourcesStructLocked", activityToken); //noinspection unchecked - resourceReferences = (ArrayList>) getObjectField(activityResources, "activityResources"); + resourceReferences = (ArrayList) getObjectField(activityResources, "activityResources"); } else { //noinspection unchecked - resourceReferences = (ArrayList>) getObjectField(param.thisObject, "mResourceReferences"); + resourceReferences = (ArrayList) getObjectField(param.thisObject, "mResourceReferences"); + } + if (classActivityRes == null) { + resourceReferences.add(new WeakReference<>(newRes)); + } else { + var activityRes = XposedHelpers.newInstance(classActivityRes); + XposedHelpers.setObjectField(activityRes, "resources", new WeakReference<>(newRes)); } - resourceReferences.add(new WeakReference<>(newRes)); } } - }); + }; + + for (var createResourceMethod : createResourceMethods) { + hookAllMethods(classGTLR, createResourceMethod, hooker); + } findAndHookMethod(TypedArray.class, "obtain", Resources.class, int.class, new XC_MethodHook() {