Dynamically create XResourcesSuperClass and XTypedArraySuperClass
To support ROMs using custom Resources subclasses.
This commit is contained in:
parent
ee4d48c1b4
commit
7d5a72b683
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ android {
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '28.0.3'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 23
|
minSdkVersion 26
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue