[core] Fix resource hook in Android 12 (#1270)

This commit is contained in:
LoveSy 2021-10-14 19:45:32 +08:00 committed by GitHub
parent 4dc0705e75
commit 2388517b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 39 additions and 14 deletions

View File

@ -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<Object> latestResKey = new ThreadLocal<>();
final String createResourceMethod;
final ArrayList<String> 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<Class<?>>) () -> {
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<WeakReference<Resources>> resourceReferences;
ArrayList<Object> resourceReferences;
if (activityToken != null) {
Object activityResources = callMethod(param.thisObject, "getOrCreateActivityResourcesStructLocked", activityToken);
//noinspection unchecked
resourceReferences = (ArrayList<WeakReference<Resources>>) getObjectField(activityResources, "activityResources");
resourceReferences = (ArrayList<Object>) getObjectField(activityResources, "activityResources");
} else {
//noinspection unchecked
resourceReferences = (ArrayList<WeakReference<Resources>>) getObjectField(param.thisObject, "mResourceReferences");
resourceReferences = (ArrayList<Object>) 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() {