Dynamically create XResourcesSuperClass and XTypedArraySuperClass

To support ROMs using custom Resources subclasses.
This commit is contained in:
solohsu 2019-04-29 23:16:24 +08:00
parent ee4d48c1b4
commit 7d5a72b683
10 changed files with 79 additions and 29 deletions

View File

@ -33,9 +33,10 @@ public class Router {
static boolean useSandHook = false; static boolean useSandHook = false;
public static void prepare(boolean isSystem) { public static void prepare(boolean isSystem) {
startWorkAroundHook();
XposedBridge.initXResources();
// this flag is needed when loadModules // this flag is needed when loadModules
startsSystemServer = isSystem; startsSystemServer = isSystem;
// InstallerChooser.setup();
} }
public static void checkHookState(String appDataDir) { public static void checkHookState(String appDataDir) {

View File

@ -27,9 +27,10 @@ public class Router {
public static void prepare(boolean isSystem) { public static void prepare(boolean isSystem) {
startWorkAroundHook();
XposedBridge.initXResources();
// this flag is needed when loadModules // this flag is needed when loadModules
XposedInit.startsSystemServer = isSystem; XposedInit.startsSystemServer = isSystem;
// InstallerChooser.setup();
} }
public static void checkHookState(String appDataDir) { public static void checkHookState(String appDataDir) {

View File

@ -29,9 +29,10 @@ public class Router {
public static void prepare(boolean isSystem) { public static void prepare(boolean isSystem) {
startWorkAroundHook();
XposedBridge.initXResources();
// this flag is needed when loadModules // this flag is needed when loadModules
XposedInit.startsSystemServer = isSystem; XposedInit.startsSystemServer = isSystem;
// InstallerChooser.setup();
} }
public static void checkHookState(String appDataDir) { public static void checkHookState(String appDataDir) {

View File

@ -16,4 +16,9 @@ public class XResourcesSuperClass extends Resources {
super(null, null, null); super(null, null, null);
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
protected XResourcesSuperClass(ClassLoader classLoader) {
super(classLoader);
throw new UnsupportedOperationException();
}
} }

View File

@ -13,8 +13,8 @@ import android.content.res.TypedArray;
*/ */
public class XTypedArraySuperClass extends TypedArray { public class XTypedArraySuperClass extends TypedArray {
/** Dummy, will never be called (objects are transferred to this class only). */ /** Dummy, will never be called (objects are transferred to this class only). */
protected XTypedArraySuperClass(Resources resources, int[] data, int[] indices, int len) { protected XTypedArraySuperClass(Resources resources) {
super(null, null, null, 0); super(resources);
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }

View File

@ -5,7 +5,7 @@ android {
buildToolsVersion '28.0.3' buildToolsVersion '28.0.3'
defaultConfig { defaultConfig {
minSdkVersion 23 minSdkVersion 26
} }
sourceSets { sourceSets {

View File

@ -33,6 +33,8 @@ import de.robv.android.xposed.XposedBridge.CopyOnWriteSortedSet;
import de.robv.android.xposed.callbacks.XC_LayoutInflated; import de.robv.android.xposed.callbacks.XC_LayoutInflated;
import de.robv.android.xposed.callbacks.XC_LayoutInflated.LayoutInflatedParam; import de.robv.android.xposed.callbacks.XC_LayoutInflated.LayoutInflatedParam;
import de.robv.android.xposed.callbacks.XCallback; import de.robv.android.xposed.callbacks.XCallback;
import xposed.dummy.XResourcesSuperClass;
import xposed.dummy.XTypedArraySuperClass;
import static de.robv.android.xposed.XposedHelpers.decrementMethodDepth; import static de.robv.android.xposed.XposedHelpers.decrementMethodDepth;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
@ -49,7 +51,7 @@ import static de.robv.android.xposed.XposedHelpers.incrementMethodDepth;
* be set using the methods made available via the API methods in this class. * be set using the methods made available via the API methods in this class.
*/ */
@SuppressWarnings("JniMissingFunction") @SuppressWarnings("JniMissingFunction")
public class XResources extends Resources { public class XResources extends XResourcesSuperClass {
private static final SparseArray<HashMap<String, Object>> sReplacements = new SparseArray<>(); private static final SparseArray<HashMap<String, Object>> sReplacements = new SparseArray<>();
private static final SparseArray<HashMap<String, ResourceNames>> sResourceNames = new SparseArray<>(); private static final SparseArray<HashMap<String, ResourceNames>> sResourceNames = new SparseArray<>();
@ -77,10 +79,6 @@ public class XResources extends Resources {
private String mResDir; private String mResDir;
private String mPackageName; private String mPackageName;
public XResources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
super(assets, metrics, config);
}
public XResources(ClassLoader classLoader) { public XResources(ClassLoader classLoader) {
super(classLoader); super(classLoader);
} }
@ -1258,7 +1256,7 @@ public class XResources extends Resources {
* Mainly used when inflating layouts. * Mainly used when inflating layouts.
* @hide * @hide
*/ */
public static class XTypedArray extends TypedArray { public static class XTypedArray extends XTypedArraySuperClass {
public XTypedArray(Resources resources) { public XTypedArray(Resources resources) {
super(resources); super(resources);

View File

@ -1,29 +1,33 @@
package de.robv.android.xposed; package de.robv.android.xposed;
import android.annotation.SuppressLint; import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.Log; import android.util.Log;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject; import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import dalvik.system.InMemoryDexClassLoader;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam; import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitPackageResources;
import de.robv.android.xposed.callbacks.XC_LoadPackage; import de.robv.android.xposed.callbacks.XC_LoadPackage;
import external.com.android.dx.DexMaker;
import external.com.android.dx.TypeId;
import static de.robv.android.xposed.XposedHelpers.getIntField; import static de.robv.android.xposed.XposedHelpers.getIntField;
import static de.robv.android.xposed.XposedHelpers.setObjectField;
/** /**
* This class contains most of Xposed's central logic, such as initialization and callbacks used by * This class contains most of Xposed's central logic, such as initialization and callbacks used by
@ -83,16 +87,52 @@ public final class XposedBridge {
// } // }
// } // }
private static void initXResources() throws IOException { public static volatile ClassLoader dummyClassLoader = null;
// ed: no support for now
}
@SuppressLint("SetWorldReadable") public static void initXResources() {
private static File ensureSuperDexFile(String clz, Class<?> realSuperClz, Class<?> topClz) throws IOException { if (disableHooks) {
XposedBridge.removeFinalFlagNative(realSuperClz); return;
File dexFile = DexCreator.ensure(clz, realSuperClz, topClz); }
dexFile.setReadable(true, false); String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();
return dexFile; if (SELinuxHelper.getAppDataFileService().checkFileExists(BASE_DIR + "conf/disable_resources")) {
Log.w(TAG, "Found " + BASE_DIR + "conf/disable_resources, not hooking resources");
XposedInit.disableResources = true;
return;
}
if (dummyClassLoader != null) {
return;
}
try {
Resources res = Resources.getSystem();
Class resClass = res.getClass();
Class taClass = TypedArray.class;
try {
TypedArray ta = res.obtainTypedArray(res.getIdentifier(
"preloaded_drawables", "array", "android"));
taClass = ta.getClass();
ta.recycle();
} catch (Resources.NotFoundException nfe) {
XposedBridge.log(nfe);
}
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.loadClass("xposed.dummy.XResourcesSuperClass");
dummyClassLoader.loadClass("xposed.dummy.XTypedArraySuperClass");
setObjectField(myCL, "parent", dummyClassLoader);
} catch (Throwable throwable) {
XposedBridge.log(throwable);
XposedInit.disableResources = true;
}
} }
// private static boolean hadInitErrors() { // private static boolean hadInitErrors() {
@ -478,7 +518,9 @@ public final class XposedBridge {
private static native Object cloneToSubclassNative(Object obj, Class<?> targetClazz); private static native Object cloneToSubclassNative(Object obj, Class<?> targetClazz);
private static native void removeFinalFlagNative(Class<?> clazz); private static void removeFinalFlagNative(Class clazz) {
EdXpConfigGlobal.getHookProvider().removeFinalFlagNative(clazz);
}
// /*package*/ static native void closeFilesBeforeForkNative(); // /*package*/ static native void closeFilesBeforeForkNative();
// /*package*/ static native void reopenFilesAfterForkNative(); // /*package*/ static native void reopenFilesAfterForkNative();

View File

@ -57,8 +57,7 @@ public final class XposedInit {
private static final String startClassName = ""; // ed: no support for tool process anymore private static final String startClassName = ""; // ed: no support for tool process anymore
private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication"; private static final String INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// TODO not supported yet public static boolean disableResources = false;
private static boolean disableResources = false;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"}; private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
private XposedInit() { private XposedInit() {
@ -86,8 +85,11 @@ public final class XposedInit {
hookResources(); hookResources();
} }
/*package*/ private static void hookResources() throws Throwable {
public static void hookResources() throws Throwable {
if (disableResources) {
return;
}
String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir(); String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();