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;
public static void prepare(boolean isSystem) {
startWorkAroundHook();
XposedBridge.initXResources();
// this flag is needed when loadModules
startsSystemServer = isSystem;
// InstallerChooser.setup();
}
public static void checkHookState(String appDataDir) {

View File

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

View File

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

View File

@ -16,4 +16,9 @@ public class XResourcesSuperClass extends Resources {
super(null, null, null);
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 {
/** Dummy, will never be called (objects are transferred to this class only). */
protected XTypedArraySuperClass(Resources resources, int[] data, int[] indices, int len) {
super(null, null, null, 0);
protected XTypedArraySuperClass(Resources resources) {
super(resources);
throw new UnsupportedOperationException();
}
}

View File

@ -5,7 +5,7 @@ android {
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 23
minSdkVersion 26
}
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.LayoutInflatedParam;
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.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.
*/
@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, ResourceNames>> sResourceNames = new SparseArray<>();
@ -77,10 +79,6 @@ public class XResources extends Resources {
private String mResDir;
private String mPackageName;
public XResources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
super(assets, metrics, config);
}
public XResources(ClassLoader classLoader) {
super(classLoader);
}
@ -1258,7 +1256,7 @@ public class XResources extends Resources {
* Mainly used when inflating layouts.
* @hide
*/
public static class XTypedArray extends TypedArray {
public static class XTypedArray extends XTypedArraySuperClass {
public XTypedArray(Resources resources) {
super(resources);

View File

@ -1,29 +1,33 @@
package de.robv.android.xposed;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.Log;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import dalvik.system.InMemoryDexClassLoader;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
import de.robv.android.xposed.callbacks.XC_InitPackageResources;
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.setObjectField;
/**
* 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 {
// ed: no support for now
}
public static volatile ClassLoader dummyClassLoader = null;
@SuppressLint("SetWorldReadable")
private static File ensureSuperDexFile(String clz, Class<?> realSuperClz, Class<?> topClz) throws IOException {
XposedBridge.removeFinalFlagNative(realSuperClz);
File dexFile = DexCreator.ensure(clz, realSuperClz, topClz);
dexFile.setReadable(true, false);
return dexFile;
public static void initXResources() {
if (disableHooks) {
return;
}
String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();
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() {
@ -478,7 +518,9 @@ public final class XposedBridge {
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 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 INSTANT_RUN_CLASS = "com.android.tools.fd.runtime.BootstrapApplication";
// TODO not supported yet
private static boolean disableResources = false;
public static boolean disableResources = false;
private static final String[] XRESOURCES_CONFLICTING_PACKAGES = {"com.sygic.aura"};
private XposedInit() {
@ -86,8 +85,11 @@ public final class XposedInit {
hookResources();
}
/*package*/
public static void hookResources() throws Throwable {
private static void hookResources() throws Throwable {
if (disableResources) {
return;
}
String BASE_DIR = EdXpConfigGlobal.getConfig().getInstallerBaseDir();