From 8febd8cc7a151aa2e41b997c8fe909e014ea4fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=97=E5=AE=AB=E9=9B=AA=E7=8F=8A?= Date: Thu, 19 May 2022 04:57:35 +0800 Subject: [PATCH] Fix resource hook on MediaTek (#1951) --- .../de/robv/android/xposed/XposedBridge.java | 29 +++++++++++++++---- .../lspd/service/ConfigFileManager.java | 24 +++++++++++++-- 2 files changed, 46 insertions(+), 7 deletions(-) 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 176d8239..16e9ecf2 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -20,10 +20,11 @@ package de.robv.android.xposed; -import static de.robv.android.xposed.XposedHelpers.setObjectField; - import android.app.ActivityThread; +import android.content.ContextWrapper; +import android.content.pm.ApplicationInfo; import android.content.res.Resources; +import android.content.res.ResourcesImpl; import android.content.res.TypedArray; import android.util.Log; @@ -50,7 +51,6 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage; * This class contains most of Xposed's central logic, such as initialization and callbacks used by * the native side. It also includes methods to add new hooks. */ -@SuppressWarnings("JniMissingFunction") public final class XposedBridge { /** * The system class loader which can be used to locate Android framework classes. @@ -133,10 +133,29 @@ public final class XposedBridge { ResourcesHook.makeInheritable(resClass); ResourcesHook.makeInheritable(taClass); ClassLoader myCL = XposedBridge.class.getClassLoader(); + assert myCL != null; dummyClassLoader = ResourcesHook.buildDummyClassLoader(myCL.getParent(), resClass.getName(), taClass.getName()); dummyClassLoader.loadClass("xposed.dummy.XResourcesSuperClass"); dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass"); - setObjectField(myCL, "parent", dummyClassLoader); + XposedHelpers.setObjectField(myCL, "parent", dummyClassLoader); + + var contextField = XposedHelpers.findFieldIfExists(ResourcesImpl.class, "mAppContext"); + // Used by com.mediatek.res.AsyncDrawableCache.putCacheList + if (contextField != null) { + var mediatekCompat = new ContextWrapper(null) { + private final ApplicationInfo info = new ApplicationInfo(); + + @Override + public ApplicationInfo getApplicationInfo() { + info.processName = "system"; + return info; + } + }; + + // This field will be updated to correct value + // after ContextImpl.createAppContext + contextField.set(null, mediatekCompat); + } } catch (Throwable throwable) { XposedBridge.log(throwable); XposedInit.disableResources = true; @@ -405,7 +424,7 @@ public final class XposedBridge { } else { returnType = null; } - params = new Object[] { + params = new Object[]{ method, returnType, isStatic, diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index cb22b8a4..986d8131 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -22,11 +22,13 @@ package org.lsposed.lspd.service; import static org.lsposed.lspd.service.ServiceManager.TAG; import static org.lsposed.lspd.service.ServiceManager.toGlobalNamespace; +import android.content.ContextWrapper; +import android.content.pm.ApplicationInfo; import android.content.res.AssetManager; import android.content.res.Resources; +import android.content.res.ResourcesImpl; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.RemoteException; import android.os.SELinux; import android.os.SharedMemory; import android.system.ErrnoException; @@ -134,12 +136,30 @@ public class ConfigFileManager { Method addAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class); addAssetPath.setAccessible(true); //noinspection ConstantConditions - if ((int) addAssetPath.invoke(am, daemonApkPath.toString()) > 0) + if ((int) addAssetPath.invoke(am, daemonApkPath.toString()) > 0) { //noinspection deprecation res = new Resources(am, null, null); + } } catch (Throwable e) { Log.e(TAG, Log.getStackTraceString(e)); } + try { + @SuppressWarnings("JavaReflectionMemberAccess") + var contextField = ResourcesImpl.class.getDeclaredField("mAppContext"); + contextField.setAccessible(true); + var mediatekCompat = new ContextWrapper(null) { + private final ApplicationInfo info = new ApplicationInfo(); + + @Override + public ApplicationInfo getApplicationInfo() { + info.processName = "system"; + return info; + } + }; + contextField.set(null, mediatekCompat); + } catch (Exception ignored) { + // Not a MediaTek device + } } static void reloadConfiguration() {