diff --git a/core/src/main/java/android/app/AndroidAppHelper.java b/core/src/main/java/android/app/AndroidAppHelper.java index e482921d..568d42e4 100644 --- a/core/src/main/java/android/app/AndroidAppHelper.java +++ b/core/src/main/java/android/app/AndroidAppHelper.java @@ -56,69 +56,16 @@ public final class AndroidAppHelper { private static final boolean HAS_THEME_CONFIG_PARAMETER; static { - CLASS_RESOURCES_KEY = (Build.VERSION.SDK_INT < 19) ? - findClass("android.app.ActivityThread$ResourcesKey", null) - : findClass("android.content.res.ResourcesKey", null); + CLASS_RESOURCES_KEY = findClass("android.content.res.ResourcesKey", null); HAS_IS_THEMEABLE = findFieldIfExists(CLASS_RESOURCES_KEY, "mIsThemeable") != null; - HAS_THEME_CONFIG_PARAMETER = HAS_IS_THEMEABLE && Build.VERSION.SDK_INT >= 21 - && findMethodExactIfExists("android.app.ResourcesManager", null, "getThemeConfig") != null; + HAS_THEME_CONFIG_PARAMETER = HAS_IS_THEMEABLE && findMethodExactIfExists("android.app.ResourcesManager", null, "getThemeConfig") != null; } @SuppressWarnings({ "unchecked", "rawtypes" }) private static Map getResourcesMap(ActivityThread activityThread) { - if (Build.VERSION.SDK_INT >= 24) { - Object resourcesManager = getObjectField(activityThread, "mResourcesManager"); - return (Map) getObjectField(resourcesManager, "mResourceImpls"); - } else if (Build.VERSION.SDK_INT >= 19) { - Object resourcesManager = getObjectField(activityThread, "mResourcesManager"); - return (Map) getObjectField(resourcesManager, "mActiveResources"); - } else { - return (Map) getObjectField(activityThread, "mActiveResources"); - } - } - - /* For SDK 15 & 16 */ - private static Object createResourcesKey(String resDir, float scale) { - try { - if (HAS_IS_THEMEABLE) - return newInstance(CLASS_RESOURCES_KEY, resDir, scale, false); - else - return newInstance(CLASS_RESOURCES_KEY, resDir, scale); - } catch (Throwable t) { - XposedBridge.log(t); - return null; - } - } - - /* For SDK 17 & 18 & 23 */ - private static Object createResourcesKey(String resDir, int displayId, Configuration overrideConfiguration, float scale) { - try { - if (HAS_THEME_CONFIG_PARAMETER) - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale, false, null); - else if (HAS_IS_THEMEABLE) - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale, false); - else - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale); - } catch (Throwable t) { - XposedBridge.log(t); - return null; - } - } - - /* For SDK 19 - 22 */ - private static Object createResourcesKey(String resDir, int displayId, Configuration overrideConfiguration, float scale, IBinder token) { - try { - if (HAS_THEME_CONFIG_PARAMETER) - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale, false, null, token); - else if (HAS_IS_THEMEABLE) - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale, false, token); - else - return newInstance(CLASS_RESOURCES_KEY, resDir, displayId, overrideConfiguration, scale, token); - } catch (Throwable t) { - XposedBridge.log(t); - return null; - } + Object resourcesManager = getObjectField(activityThread, "mResourcesManager"); + return (Map) getObjectField(resourcesManager, "mResourceImpls"); } /* For SDK 24+ */ @@ -144,27 +91,13 @@ public final class AndroidAppHelper { } Object resourcesKey; - if (Build.VERSION.SDK_INT >= 24) { - CompatibilityInfo compatInfo = (CompatibilityInfo) newInstance(CompatibilityInfo.class); - setFloatField(compatInfo, "applicationScale", resources.hashCode()); - resourcesKey = createResourcesKey(resDir, null, null, null, Display.DEFAULT_DISPLAY, null, compatInfo); - } else if (Build.VERSION.SDK_INT == 23) { - resourcesKey = createResourcesKey(resDir, Display.DEFAULT_DISPLAY, null, resources.hashCode()); - } else if (Build.VERSION.SDK_INT >= 19) { - resourcesKey = createResourcesKey(resDir, Display.DEFAULT_DISPLAY, null, resources.hashCode(), null); - } else if (Build.VERSION.SDK_INT >= 17) { - resourcesKey = createResourcesKey(resDir, Display.DEFAULT_DISPLAY, null, resources.hashCode()); - } else { - resourcesKey = createResourcesKey(resDir, resources.hashCode()); - } + CompatibilityInfo compatInfo = (CompatibilityInfo) newInstance(CompatibilityInfo.class); + setFloatField(compatInfo, "applicationScale", resources.hashCode()); + resourcesKey = createResourcesKey(resDir, null, null, null, Display.DEFAULT_DISPLAY, null, compatInfo); if (resourcesKey != null) { - if (Build.VERSION.SDK_INT >= 24) { - Object resImpl = getObjectField(resources, "mResourcesImpl"); - getResourcesMap(thread).put(resourcesKey, new WeakReference<>(resImpl)); - } else { - getResourcesMap(thread).put(resourcesKey, new WeakReference<>(resources)); - } + Object resImpl = getObjectField(resources, "mResourcesImpl"); + getResourcesMap(thread).put(resourcesKey, new WeakReference<>(resImpl)); } } diff --git a/core/src/main/java/android/content/res/XResources.java b/core/src/main/java/android/content/res/XResources.java index eb45e3f3..24a4d69d 100644 --- a/core/src/main/java/android/content/res/XResources.java +++ b/core/src/main/java/android/content/res/XResources.java @@ -119,11 +119,7 @@ public class XResources extends XResourcesSuperClass { if (resDir != null) { synchronized (sReplacementsCacheMap) { - mReplacementsCache = sReplacementsCacheMap.get(resDir); - if (mReplacementsCache == null) { - mReplacementsCache = new byte[128]; - sReplacementsCacheMap.put(resDir, mReplacementsCache); - } + mReplacementsCache = sReplacementsCacheMap.computeIfAbsent(resDir, k -> new byte[128]); } } @@ -184,14 +180,10 @@ public class XResources extends XResourcesSuperClass { return packageName; PackageParser.PackageLite pkgInfo; - if (Build.VERSION.SDK_INT >= 21) { - try { - pkgInfo = PackageParser.parsePackageLite(new File(resDir), 0); - } catch (PackageParserException e) { - throw new IllegalStateException("Could not determine package name for " + resDir, e); - } - } else { - pkgInfo = PackageParser.parsePackageLite(resDir, 0); + try { + pkgInfo = PackageParser.parsePackageLite(new File(resDir), 0); + } catch (PackageParserException e) { + throw new IllegalStateException("Could not determine package name for " + resDir, e); } if (pkgInfo != null && pkgInfo.packageName != null) { // Log.w(XposedBridge.TAG, "Package name for " + resDir + " had to be retrieved via parser"); @@ -265,7 +257,7 @@ public class XResources extends XResourcesSuperClass { XMLInstanceDetails details = (XMLInstanceDetails) param.getObjectExtra(EXTRA_XML_INSTANCE_DETAILS); if (details != null) { LayoutInflatedParam liparam = new LayoutInflatedParam(details.callbacks); - ViewGroup group = (ViewGroup) param.args[(Build.VERSION.SDK_INT < 23) ? 1 : 2]; + ViewGroup group = (ViewGroup) param.args[2]; liparam.view = group.getChildAt(group.getChildCount() - 1); liparam.resNames = details.resNames; liparam.variant = details.variant; @@ -274,16 +266,8 @@ public class XResources extends XResourcesSuperClass { } } }; - if (Build.VERSION.SDK_INT < 21) { - findAndHookMethod(LayoutInflater.class, "parseInclude", XmlPullParser.class, View.class, - AttributeSet.class, parseIncludeHook); - } else if (Build.VERSION.SDK_INT < 23) { - findAndHookMethod(LayoutInflater.class, "parseInclude", XmlPullParser.class, View.class, - AttributeSet.class, boolean.class, parseIncludeHook); - } else { - findAndHookMethod(LayoutInflater.class, "parseInclude", XmlPullParser.class, Context.class, - View.class, AttributeSet.class, parseIncludeHook); - } + findAndHookMethod(LayoutInflater.class, "parseInclude", XmlPullParser.class, Context.class, + View.class, AttributeSet.class, parseIncludeHook); } /** @@ -662,9 +646,7 @@ public class XResources extends XResourcesSuperClass { XmlResourceParser result = repRes.getAnimation(repId); if (!loadedFromCache) { - long parseState = (Build.VERSION.SDK_INT >= 21) - ? getLongField(result, "mParseState") - : getIntField(result, "mParseState"); + long parseState = getLongField(result, "mParseState"); rewriteXmlReferencesNative(parseState, this, repRes); } @@ -924,9 +906,7 @@ public class XResources extends XResourcesSuperClass { result = repRes.getLayout(repId); if (!loadedFromCache) { - long parseState = (Build.VERSION.SDK_INT >= 21) - ? getLongField(result, "mParseState") - : getIntField(result, "mParseState"); + long parseState = getLongField(result, "mParseState"); rewriteXmlReferencesNative(parseState, this, repRes); } } else { @@ -1080,9 +1060,7 @@ public class XResources extends XResourcesSuperClass { XmlResourceParser result = repRes.getXml(repId); if (!loadedFromCache) { - long parseState = (Build.VERSION.SDK_INT >= 21) - ? getLongField(result, "mParseState") - : getIntField(result, "mParseState"); + long parseState = getLongField(result, "mParseState"); rewriteXmlReferencesNative(parseState, this, repRes); } diff --git a/core/src/main/java/de/robv/android/xposed/DexCreator.java b/core/src/main/java/de/robv/android/xposed/DexCreator.java deleted file mode 100644 index 95e06798..00000000 --- a/core/src/main/java/de/robv/android/xposed/DexCreator.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -package de.robv.android.xposed; - -import android.os.Environment; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.Adler32; - -import static de.robv.android.xposed.XposedHelpers.inputStreamToByteArray; - -/** - * Helper class which can create a very simple .dex file, containing only a class definition - * with a super class (no methods, fields, ...). - */ -/*package*/ class DexCreator { - public static File DALVIK_CACHE = new File(Environment.getDataDirectory(), "dalvik-cache"); - - /** Returns the default dex file name for the class. */ - public static File getDefaultFile(String childClz) { - return new File(DALVIK_CACHE, "xposed_" + childClz.substring(childClz.lastIndexOf('.') + 1) + ".dex"); - } - - /** - * Creates (or returns) the path to a dex file which defines the superclass of {@clz} as extending - * {@code realSuperClz}, which by itself must extend {@code topClz}. - */ - public static File ensure(String clz, Class realSuperClz, Class topClz) throws IOException { - if (!topClz.isAssignableFrom(realSuperClz)) { - throw new ClassCastException("Cannot initialize " + clz + " because " + realSuperClz + " does not extend " + topClz); - } - - try { - return ensure("xposed.dummy." + clz + "SuperClass", realSuperClz); - } catch (IOException e) { - throw new IOException("Failed to create a superclass for " + clz, e); - } - } - - /** Like {@link #ensure(File, String, String)}, just for the default dex file name. */ - public static File ensure(String childClz, Class superClz) throws IOException { - return ensure(getDefaultFile(childClz), childClz, superClz.getName()); - } - - /** - * Makes sure that the given file is a simple dex file containing the given classes. - * Creates the file if that's not the case. - */ - public static File ensure(File file, String childClz, String superClz) throws IOException { - // First check if a valid file exists. - try { - byte[] dex = inputStreamToByteArray(new FileInputStream(file)); - if (matches(dex, childClz, superClz)) { - return file; - } else { - file.delete(); - } - } catch (IOException e) { - file.delete(); - } - - // If not, create a new dex file. - byte[] dex = create(childClz, superClz); - FileOutputStream fos = new FileOutputStream(file); - fos.write(dex); - fos.close(); - return file; - } - - /** - * Checks whether the Dex file fits to the class names. - * Assumes that the file has been created with this class. - */ - public static boolean matches(byte[] dex, String childClz, String superClz) throws IOException { - boolean childFirst = childClz.compareTo(superClz) < 0; - byte[] childBytes = stringToBytes("L" + childClz.replace('.', '/') + ";"); - byte[] superBytes = stringToBytes("L" + superClz.replace('.', '/') + ";"); - - int pos = 0xa0; - if (pos + childBytes.length + superBytes.length >= dex.length) { - return false; - } - - for (byte b : childFirst ? childBytes : superBytes) { - if (dex[pos++] != b) { - return false; - } - } - - for (byte b : childFirst ? superBytes: childBytes) { - if (dex[pos++] != b) { - return false; - } - } - - return true; - } - - /** Creates the byte array for the dex file. */ - public static byte[] create(String childClz, String superClz) throws IOException { - boolean childFirst = childClz.compareTo(superClz) < 0; - byte[] childBytes = stringToBytes("L" + childClz.replace('.', '/') + ";"); - byte[] superBytes = stringToBytes("L" + superClz.replace('.', '/') + ";"); - int stringsSize = childBytes.length + superBytes.length; - int padding = -stringsSize & 3; - stringsSize += padding; - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - // header - out.write("dex\n035\0".getBytes()); // magic - out.write(new byte[24]); // placeholder for checksum and signature - writeInt(out, 0xfc + stringsSize); // file size - writeInt(out, 0x70); // header size - writeInt(out, 0x12345678); // endian constant - writeInt(out, 0); // link size - writeInt(out, 0); // link offset - writeInt(out, 0xa4 + stringsSize); // map offset - writeInt(out, 2); // strings count - writeInt(out, 0x70); // strings offset - writeInt(out, 2); // types count - writeInt(out, 0x78); // types offset - writeInt(out, 0); // prototypes count - writeInt(out, 0); // prototypes offset - writeInt(out, 0); // fields count - writeInt(out, 0); // fields offset - writeInt(out, 0); // methods count - writeInt(out, 0); // methods offset - writeInt(out, 1); // classes count - writeInt(out, 0x80); // classes offset - writeInt(out, 0x5c + stringsSize); // data size - writeInt(out, 0xa0); // data offset - - // string map - writeInt(out, 0xa0); - writeInt(out, 0xa0 + (childFirst ? childBytes.length : superBytes.length)); - - // types - writeInt(out, 0); // first type = first string - writeInt(out, 1); // second type = second string - - // class definitions - writeInt(out, childFirst ? 0 : 1); // class to define = child type - writeInt(out, 1); // access flags = public - writeInt(out, childFirst ? 1 : 0); // super class = super type - writeInt(out, 0); // no interface - writeInt(out, -1); // no source file - writeInt(out, 0); // no annotations - writeInt(out, 0); // no class data - writeInt(out, 0); // no static values - - // string data - out.write(childFirst ? childBytes : superBytes); - out.write(childFirst ? superBytes : childBytes); - out.write(new byte[padding]); - - // annotations - writeInt(out, 0); // no items - - // map - writeInt(out, 7); // items count - writeMapItem(out, 0, 1, 0); // header - writeMapItem(out, 1, 2, 0x70); // strings - writeMapItem(out, 2, 2, 0x78); // types - writeMapItem(out, 6, 1, 0x80); // classes - writeMapItem(out, 0x2002, 2, 0xa0); // string data - writeMapItem(out, 0x1003, 1, 0xa0 + stringsSize); // annotations - writeMapItem(out, 0x1000, 1, 0xa4 + stringsSize); // map list - - byte[] buf = out.toByteArray(); - updateSignature(buf); - updateChecksum(buf); - return buf; - } - - private static void updateSignature(byte[] dex) { - // Update SHA-1 signature - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - md.update(dex, 32, dex.length - 32); - md.digest(dex, 12, 20); - } catch (NoSuchAlgorithmException | DigestException e) { - throw new RuntimeException(e); - } - } - - private static void updateChecksum(byte[] dex) { - // Update Adler32 checksum - Adler32 a32 = new Adler32(); - a32.update(dex, 12, dex.length - 12); - int chksum = (int) a32.getValue(); - dex[8] = (byte) (chksum & 0xff); - dex[9] = (byte) (chksum >> 8 & 0xff); - dex[10] = (byte) (chksum >> 16 & 0xff); - dex[11] = (byte) (chksum >> 24 & 0xff); - } - - private static void writeUleb128(OutputStream out, int value) throws IOException { - while (value > 0x7f) { - out.write((value & 0x7f) | 0x80); - value >>>= 7; - } - out.write(value); - } - - private static void writeInt(OutputStream out, int value) throws IOException { - out.write(value); - out.write(value >> 8); - out.write(value >> 16); - out.write(value >> 24); - } - - private static void writeMapItem(OutputStream out, int type, int count, int offset) throws IOException { - writeInt(out, type); - writeInt(out, count); - writeInt(out, offset); - } - - private static byte[] stringToBytes(String s) throws IOException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - writeUleb128(bytes, s.length()); - // This isn't MUTF-8, but should be OK. - bytes.write(s.getBytes("UTF-8")); - bytes.write(0); - return bytes.toByteArray(); - } - - private DexCreator() {} -} diff --git a/core/src/main/java/de/robv/android/xposed/PendingHooks.java b/core/src/main/java/de/robv/android/xposed/PendingHooks.java index deb7f8f0..5db980c0 100644 --- a/core/src/main/java/de/robv/android/xposed/PendingHooks.java +++ b/core/src/main/java/de/robv/android/xposed/PendingHooks.java @@ -24,9 +24,9 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import static de.robv.android.xposed.XposedBridge.hookMethodNative; +import io.github.lsposed.lspd.config.LSPdConfigGlobal; + import static io.github.lsposed.lspd.nativebridge.PendingHooks.recordPendingMethodNative; public final class PendingHooks { @@ -38,7 +38,7 @@ public final class PendingHooks { public synchronized static void hookPendingMethod(Class clazz) { if (sPendingHooks.containsKey(clazz)) { for (Map.Entry hook : sPendingHooks.get(clazz).entrySet()) { - hookMethodNative(hook.getKey(), clazz, 0, hook.getValue()); + LSPdConfigGlobal.getHookProvider().hookMethod(hook.getKey(), hook.getValue()); } sPendingHooks.remove(clazz); } @@ -47,13 +47,7 @@ public final class PendingHooks { public synchronized static void recordPendingMethod(Method hookMethod, XposedBridge.AdditionalHookInfo additionalInfo) { ConcurrentHashMap pending = - sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(), - new Function, ConcurrentHashMap>() { - @Override - public ConcurrentHashMap apply(Class aClass) { - return new ConcurrentHashMap<>(); - } - }); + sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(), aClass -> new ConcurrentHashMap<>()); pending.put(hookMethod, additionalInfo); recordPendingMethodNative(hookMethod, hookMethod.getDeclaringClass()); diff --git a/core/src/main/java/de/robv/android/xposed/SELinuxHelper.java b/core/src/main/java/de/robv/android/xposed/SELinuxHelper.java index dc5749fd..0156c0f3 100644 --- a/core/src/main/java/de/robv/android/xposed/SELinuxHelper.java +++ b/core/src/main/java/de/robv/android/xposed/SELinuxHelper.java @@ -20,12 +20,6 @@ package de.robv.android.xposed; -import android.os.SELinux; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - import de.robv.android.xposed.services.BaseService; import de.robv.android.xposed.services.DirectAccessService; @@ -41,7 +35,8 @@ public final class SELinuxHelper { * @return A boolean indicating whether SELinux is enabled. */ public static boolean isSELinuxEnabled() { - return sIsSELinuxEnabled; + // lsp: always enabled + return true; } /** @@ -50,36 +45,8 @@ public final class SELinuxHelper { * @return A boolean indicating whether SELinux is enforcing. */ public static boolean isSELinuxEnforced() { - if (!sIsSELinuxEnabled) { - return false; - } - boolean result = false; - final File SELINUX_STATUS_FILE = new File("/sys/fs/selinux/enforce"); - if (SELINUX_STATUS_FILE.exists()) { - try { - FileInputStream fis = new FileInputStream(SELINUX_STATUS_FILE); - int status = fis.read(); - switch (status) { - case 49: - result = true; - break; - case 48: - result = false; - break; - default: - XposedBridge.log("Unexpected byte " + status + " in /sys/fs/selinux/enforce"); - } - fis.close(); - } catch (IOException e) { - if (e.getMessage().contains("Permission denied")) { - result = true; - } else { - XposedBridge.log("Failed to read SELinux status: " + e.getMessage()); - result = false; - } - } - } - return result; + // lsp: always enforcing + return true; } /** @@ -88,7 +55,7 @@ public final class SELinuxHelper { * @return A String representing the security context of the current process. */ public static String getContext() { - return sIsSELinuxEnabled ? SELinux.getContext() : null; + return null; } /** @@ -100,36 +67,9 @@ public final class SELinuxHelper { * @return An instance of the service. */ public static BaseService getAppDataFileService() { - if (sServiceAppDataFile != null) - return sServiceAppDataFile; - throw new UnsupportedOperationException(); - } + return sServiceAppDataFile; + } + private static final BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly - // ---------------------------------------------------------------------------- - // TODO: SELinux status - private static boolean sIsSELinuxEnabled = false; - private static BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly - - /*package*/ public static void initOnce() { - // ed: we assume all selinux policies have been added lively using magiskpolicy - try { - sIsSELinuxEnabled = SELinux.isSELinuxEnabled(); - } catch (NoClassDefFoundError ignored) {} - } - - /*package*/ static void initForProcess(String packageName) { - // ed: sServiceAppDataFile has been initialized with default value -// if (sIsSELinuxEnabled) { -// if (packageName == null) { // Zygote -// sServiceAppDataFile = new ZygoteService(); -// } else if (packageName.equals("android")) { //system_server -// sServiceAppDataFile = BinderService.getService(BinderService.TARGET_APP); -// } else { // app -// sServiceAppDataFile = new DirectAccessService(); -// } -// } else { -// sServiceAppDataFile = new DirectAccessService(); -// } - } } 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 f359309a..aa1af28f 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/core/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -41,18 +41,15 @@ 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.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitZygote; import de.robv.android.xposed.callbacks.XC_LoadPackage; -import de.robv.android.xposed.callbacks.XCallback; import external.com.android.dx.DexMaker; import external.com.android.dx.TypeId; import io.github.lsposed.lspd.nativebridge.ModuleLogger; -import static de.robv.android.xposed.XposedHelpers.getIntField; import static de.robv.android.xposed.XposedHelpers.setObjectField; /** @@ -78,10 +75,6 @@ public final class XposedBridge { /*package*/ static boolean isZygote = true; // ed: RuntimeInit.main() tool process not supported yet - private static int runtime = 2; // ed: only support art - private static final int RUNTIME_DALVIK = 1; - private static final int RUNTIME_ART = 2; - // This field is set "magically" on MIUI. /*package*/ static long BOOT_START_TIME; @@ -95,14 +88,6 @@ public final class XposedBridge { private XposedBridge() {} - /** @hide */ -// protected static final class ToolEntryPoint { -// protected static void main(String[] args) { -// isZygote = false; -// XposedBridge.main(args); -// } -// } - public static volatile ClassLoader dummyClassLoader = null; @ApiSensitive(Level.MIDDLE) @@ -143,15 +128,6 @@ public final class XposedBridge { } } -// private static boolean hadInitErrors() { -// // ed: assuming never had errors -// return false; -// } -// private static native int getRuntime(); -// /*package*/ static native boolean startsSystemServer(); -// /*package*/ static native String getStartClassName(); -// /*package*/ native static boolean initXResourcesNative(); - /** * Returns the currently installed version of the Xposed framework. */ @@ -227,28 +203,10 @@ public final class XposedBridge { callbacks.add(callback); if (newMethod) { - Class declaringClass = hookMethod.getDeclaringClass(); - int slot; - Class[] parameterTypes; - Class returnType; - if (runtime == RUNTIME_ART) { - slot = 0; - parameterTypes = null; - returnType = null; - } else if (hookMethod instanceof Method) { - slot = getIntField(hookMethod, "slot"); - parameterTypes = ((Method) hookMethod).getParameterTypes(); - returnType = ((Method) hookMethod).getReturnType(); - } else { - slot = getIntField(hookMethod, "slot"); - parameterTypes = ((Constructor) hookMethod).getParameterTypes(); - returnType = null; - } - - AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType); + AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks); Member reflectMethod = LSPdConfigGlobal.getHookProvider().findMethodNative(hookMethod); if (reflectMethod != null) { - hookMethodNative(reflectMethod, declaringClass, slot, additionalInfo); + LSPdConfigGlobal.getHookProvider().hookMethod(reflectMethod, (AdditionalHookInfo) additionalInfo); } else { PendingHooks.recordPendingMethod((Method)hookMethod, additionalInfo); } @@ -312,86 +270,6 @@ public final class XposedBridge { return unhooks; } - /** - * This method is called as a replacement for hooked methods. - */ - public static Object handleHookedMethod(Member method, long originalMethodId, Object additionalInfoObj, - Object thisObject, Object[] args) throws Throwable { - AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj; - - Object[] callbacksSnapshot = additionalInfo.callbacks.getSnapshot(); - final int callbacksLength = callbacksSnapshot.length; - if (callbacksLength == 0) { - try { - return invokeOriginalMethodNative(method, originalMethodId, additionalInfo.parameterTypes, - additionalInfo.returnType, thisObject, args); - } catch (InvocationTargetException e) { - throw e.getCause(); - } - } - - MethodHookParam param = new MethodHookParam(); - param.method = method; - param.thisObject = thisObject; - param.args = args; - - // call "before method" callbacks - int beforeIdx = 0; - do { - try { - ((XC_MethodHook) callbacksSnapshot[beforeIdx]).beforeHookedMethod(param); - } catch (Throwable t) { - XposedBridge.log(t); - - // reset result (ignoring what the unexpectedly exiting callback did) - param.setResult(null); - param.returnEarly = false; - continue; - } - - if (param.returnEarly) { - // skip remaining "before" callbacks and corresponding "after" callbacks - beforeIdx++; - break; - } - } while (++beforeIdx < callbacksLength); - - // call original method if not requested otherwise - if (!param.returnEarly) { - try { - param.setResult(invokeOriginalMethodNative(method, originalMethodId, - additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args)); - } catch (InvocationTargetException e) { - param.setThrowable(e.getCause()); - } - } - - // call "after method" callbacks - int afterIdx = beforeIdx - 1; - do { - Object lastResult = param.getResult(); - Throwable lastThrowable = param.getThrowable(); - - try { - ((XC_MethodHook) callbacksSnapshot[afterIdx]).afterHookedMethod(param); - } catch (Throwable t) { - XposedBridge.log(t); - - // reset to last result (ignoring what the unexpectedly exiting callback did) - if (lastThrowable == null) - param.setResult(lastResult); - else - param.setThrowable(lastThrowable); - } - } while (--afterIdx >= 0); - - // return - if (param.hasThrowable()) - throw param.getThrowable(); - else - return param.getResult(); - } - /** * Adds a callback to be executed when an app ("Android package") is loaded. * @@ -428,51 +306,12 @@ public final class XposedBridge { } } - public static void clearInitPackageResources() { - synchronized (sInitPackageResourcesCallbacks) { - sInitPackageResourcesCallbacks.clear(); - } - } - public static void hookInitZygote(XC_InitZygote callback) { synchronized (sInitZygoteCallbacks) { sInitZygoteCallbacks.add(callback); } } - public static void clearInitZygotes() { - synchronized (sInitZygoteCallbacks) { - sInitZygoteCallbacks.clear(); - } - } - - public static void callInitZygotes() { - XCallback.callAll(new IXposedHookZygoteInit.StartupParam(sInitZygoteCallbacks)); - } - - public static void clearAllCallbacks() { - clearLoadedPackages(); - clearInitPackageResources(); - clearInitZygotes(); - } - - /** - * Intercept every call to the specified method and call a handler function instead. - * @param method The method to intercept - */ - /*package*/ synchronized static void hookMethodNative(final Member method, Class declaringClass, - int slot, final Object additionalInfoObj) { - LSPdConfigGlobal.getHookProvider().hookMethod(method, (AdditionalHookInfo) additionalInfoObj); - } - - private static Object invokeOriginalMethodNative(Member method, long methodId, - Class[] parameterTypes, - Class returnType, - Object thisObject, Object[] args) - throws Throwable { - return LSPdConfigGlobal.getHookProvider().invokeOriginalMethod(method, methodId, thisObject, args); - } - /** * Basically the same as {@link Method#invoke}, but calls the original method * as it was before the interception by Xposed. Also, access permissions are not checked. @@ -504,34 +343,18 @@ public final class XposedBridge { args = EMPTY_ARRAY; } - Class[] parameterTypes; - Class returnType; - if (runtime == RUNTIME_ART && (method instanceof Method || method instanceof Constructor)) { - parameterTypes = null; - returnType = null; - } else if (method instanceof Method) { - parameterTypes = ((Method) method).getParameterTypes(); - returnType = ((Method) method).getReturnType(); - } else if (method instanceof Constructor) { - parameterTypes = ((Constructor) method).getParameterTypes(); - returnType = null; - } else { + if (!(method instanceof Method) && !(method instanceof Constructor)) { throw new IllegalArgumentException("method must be of type Method or Constructor"); } long methodId = LSPdConfigGlobal.getHookProvider().getMethodId(method); - return invokeOriginalMethodNative(method, methodId, parameterTypes, returnType, thisObject, args); + return LSPdConfigGlobal.getHookProvider().invokeOriginalMethod(method, methodId, thisObject, args); } private static void removeFinalFlagNative(Class clazz) { LSPdConfigGlobal.getHookProvider().removeFinalFlagNative(clazz); } -// /*package*/ static native void closeFilesBeforeForkNative(); -// /*package*/ static native void reopenFilesAfterForkNative(); -// -// /*package*/ static native void invalidateCallersNative(Member[] methods); - /** @hide */ public static final class CopyOnWriteSortedSet { private transient volatile Object[] elements = EMPTY_ARRAY; @@ -582,13 +405,9 @@ public final class XposedBridge { public static class AdditionalHookInfo { public final CopyOnWriteSortedSet callbacks; - public final Class[] parameterTypes; - public final Class returnType; - private AdditionalHookInfo(CopyOnWriteSortedSet callbacks, Class[] parameterTypes, Class returnType) { + private AdditionalHookInfo(CopyOnWriteSortedSet callbacks) { this.callbacks = callbacks; - this.parameterTypes = parameterTypes; - this.returnType = returnType; } } } diff --git a/core/src/main/java/de/robv/android/xposed/XposedHelpers.java b/core/src/main/java/de/robv/android/xposed/XposedHelpers.java index 83290f64..08a9df2a 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedHelpers.java +++ b/core/src/main/java/de/robv/android/xposed/XposedHelpers.java @@ -1645,70 +1645,6 @@ public final class XposedHelpers { } } - /*package*/ static boolean fileContains(File file, String str) throws IOException { - // There are certainly more efficient algorithms (e.g. Boyer-Moore used in grep), - // but the naive approach should be sufficient here. - BufferedReader in = null; - try { - in = new BufferedReader(new FileReader(file)); - String line; - while ((line = in.readLine()) != null) { - if (line.contains(str)) { - return true; - } - } - return false; - } finally { - closeSilently(in); - } - } - - //################################################################################################# - - /** - * Returns the method that is overridden by the given method. - * It returns {@code null} if the method doesn't override another method or if that method is - * abstract, i.e. if this is the first implementation in the hierarchy. - */ - /*package*/ static Method getOverriddenMethod(Method method) { - int modifiers = method.getModifiers(); - if (Modifier.isStatic(modifiers) || Modifier.isPrivate(modifiers)) { - return null; - } - - String name = method.getName(); - Class[] parameters = method.getParameterTypes(); - Class clazz = method.getDeclaringClass().getSuperclass(); - while (clazz != null) { - try { - Method superMethod = clazz.getDeclaredMethod(name, parameters); - modifiers = superMethod.getModifiers(); - if (!Modifier.isPrivate(modifiers) && !Modifier.isAbstract(modifiers)) { - return superMethod; - } else { - return null; - } - } catch (NoSuchMethodException ignored) { - clazz = clazz.getSuperclass(); - } - } - return null; - } - - /** - * Returns all methods which this class overrides. - */ - /*package*/ static Set getOverriddenMethods(Class clazz) { - Set methods = new HashSet<>(); - for (Method method : clazz.getDeclaredMethods()) { - Method overridden = getOverriddenMethod(method); - if (overridden != null) { - methods.add(overridden); - } - } - return methods; - } - //################################################################################################# // TODO helpers for view traversing /*To make it easier, I will try and implement some more helpers: diff --git a/core/src/main/java/de/robv/android/xposed/XposedInit.java b/core/src/main/java/de/robv/android/xposed/XposedInit.java index 061f75d9..0a95daa3 100644 --- a/core/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/core/src/main/java/de/robv/android/xposed/XposedInit.java @@ -20,10 +20,10 @@ package de.robv.android.xposed; -import android.app.ActivityThread; import android.app.AndroidAppHelper; import android.content.pm.ApplicationInfo; import android.content.res.Resources; +import android.content.res.ResourcesImpl; import android.content.res.TypedArray; import android.content.res.XResources; import android.os.Build; @@ -34,10 +34,10 @@ import android.util.Log; import com.android.internal.os.ZygoteInit; +import hidden.HiddenApiBridge; import io.github.lsposed.lspd.config.LSPdConfigGlobal; import java.io.BufferedReader; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -48,21 +48,18 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import dalvik.system.PathClassLoader; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; import de.robv.android.xposed.callbacks.XC_InitPackageResources; import de.robv.android.xposed.callbacks.XC_InitZygote; import de.robv.android.xposed.callbacks.XC_LoadPackage; import de.robv.android.xposed.callbacks.XCallback; import io.github.lsposed.lspd.nativebridge.NativeAPI; -import static de.robv.android.xposed.XposedBridge.hookAllConstructors; import static de.robv.android.xposed.XposedBridge.hookAllMethods; import static de.robv.android.xposed.XposedBridge.sInitPackageResourcesCallbacks; import static de.robv.android.xposed.XposedBridge.sInitZygoteCallbacks; @@ -95,7 +92,7 @@ public final class XposedInit { * Hook some methods which we want to create an easier interface for developers. */ /*package*/ - public static void initForZygote(boolean isSystem) throws Throwable { + public static void initForZygote() throws Throwable { // TODO Are these still needed for us? // MIUI if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) { @@ -147,11 +144,7 @@ public final class XposedInit { final ThreadLocal latestResKey = new ThreadLocal<>(); final String createResourceMethod; - if (Build.VERSION.SDK_INT <= 18) { - classGTLR = ActivityThread.class; - classResKey = Class.forName("android.app.ActivityThread$ResourcesKey"); - createResourceMethod = "getOrCreateResources"; - } else if (Build.VERSION.SDK_INT < 30) { + if (Build.VERSION.SDK_INT < 30) { classGTLR = Class.forName("android.app.ResourcesManager"); classResKey = Class.forName("android.content.res.ResourcesKey"); createResourceMethod = "getOrCreateResources"; @@ -161,106 +154,32 @@ public final class XposedInit { createResourceMethod = "createResources"; } - if (Build.VERSION.SDK_INT >= 24) { - hookAllMethods(classGTLR, createResourceMethod, new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - // At least on OnePlus 5, the method has an additional parameter compared to AOSP. - final int activityTokenIdx = getParameterIndexByType(param.method, IBinder.class); - final int resKeyIdx = getParameterIndexByType(param.method, classResKey); + hookAllMethods(classGTLR, createResourceMethod, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + // At least on OnePlus 5, the method has an additional parameter compared to AOSP. + final int activityTokenIdx = getParameterIndexByType(param.method, IBinder.class); + 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]; - synchronized (param.thisObject) { - ArrayList> resourceReferences; - if (activityToken != null) { - Object activityResources = callMethod(param.thisObject, "getOrCreateActivityResourcesStructLocked", activityToken); - resourceReferences = (ArrayList>) getObjectField(activityResources, "activityResources"); - } else { - resourceReferences = (ArrayList>) getObjectField(param.thisObject, "mResourceReferences"); - } - resourceReferences.add(new WeakReference(newRes)); - } - } - }); - } else { - hookAllConstructors(classResKey, new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - latestResKey.set(param.thisObject); - } - }); - - hookAllMethods(classGTLR, "getTopLevelResources", new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - latestResKey.set(null); + String resDir = (String) getObjectField(param.args[resKeyIdx], "mResDir"); + XResources newRes = cloneToXResources(param, resDir); + if (newRes == null) { + return; } - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - Object key = latestResKey.get(); - if (key == null) { - return; - } - latestResKey.set(null); - - String resDir = (String) getObjectField(key, "mResDir"); - XResources newRes = cloneToXResources(param, resDir); - if (newRes == null) { - return; - } - - @SuppressWarnings("unchecked") - Map> mActiveResources = - (Map>) getObjectField(param.thisObject, "mActiveResources"); - Object lockObject = (Build.VERSION.SDK_INT <= 18) - ? getObjectField(param.thisObject, "mPackages") : param.thisObject; - - synchronized (lockObject) { - WeakReference existing = mActiveResources.put(key, new WeakReference(newRes)); - if (existing != null && existing.get() != null && existing.get().getAssets() != newRes.getAssets()) { - existing.get().getAssets().close(); - } + Object activityToken = param.args[activityTokenIdx]; + synchronized (param.thisObject) { + ArrayList> resourceReferences; + if (activityToken != null) { + Object activityResources = callMethod(param.thisObject, "getOrCreateActivityResourcesStructLocked", activityToken); + resourceReferences = (ArrayList>) getObjectField(activityResources, "activityResources"); + } else { + resourceReferences = (ArrayList>) getObjectField(param.thisObject, "mResourceReferences"); } + resourceReferences.add(new WeakReference(newRes)); } - }); - - if (Build.VERSION.SDK_INT >= 19) { - // This method exists only on CM-based ROMs - hookAllMethods(classGTLR, "getTopLevelThemedResources", new XC_MethodHook() { - @Override - protected void afterHookedMethod(MethodHookParam param) throws Throwable { - String resDir = (String) param.args[0]; - cloneToXResources(param, resDir); - } - }); } - } - - // Invalidate callers of methods overridden by XTypedArray -// if (Build.VERSION.SDK_INT >= 24) { -// Set methods = getOverriddenMethods(XResources.XTypedArray.class); -// XposedBridge.invalidateCallersNative(methods.toArray(new Member[methods.size()])); -// } - - // Replace TypedArrays with XTypedArrays -// hookAllConstructors(TypedArray.class, new XC_MethodHook() { -// @Override -// protected void afterHookedMethod(MethodHookParam param) throws Throwable { -// TypedArray typedArray = (TypedArray) param.thisObject; -// Resources res = typedArray.getResources(); -// if (res instanceof XResources) { -// XResources.XTypedArray newTypedArray = new XResources.XTypedArray(res); -// XposedBridge.setObjectClass(typedArray, XResources.XTypedArray.class); -// } -// } -// }); + }); findAndHookMethod(TypedArray.class, "obtain", Resources.class, int.class, new XC_MethodHook() { @@ -286,8 +205,7 @@ public final class XposedInit { // Replace system resources XResources systemRes = new XResources( (ClassLoader) XposedHelpers.getObjectField(Resources.getSystem(), "mClassLoader")); - XposedHelpers.callMethod(systemRes, "setImpl", XposedHelpers.getObjectField(Resources.getSystem(), "mResourcesImpl")); - //systemRes.setImpl((ResourcesImpl) XposedHelpers.getObjectField(Resources.getSystem(), "mResourcesImpl")); + HiddenApiBridge.Resources_setImpl(systemRes, (ResourcesImpl) XposedHelpers.getObjectField(Resources.getSystem(), "mResourcesImpl")); systemRes.initObject(null); setStaticObjectField(Resources.class, "mSystem", systemRes); @@ -305,8 +223,7 @@ public final class XposedInit { // Replace the returned resources with our subclass. XResources newRes = new XResources( (ClassLoader) XposedHelpers.getObjectField(param.getResult(), "mClassLoader")); - XposedHelpers.callMethod(newRes, "setImpl", XposedHelpers.getObjectField(param.getResult(), "mResourcesImpl")); - //newRes.setImpl((ResourcesImpl) XposedHelpers.getObjectField(param.getResult(), "mResourcesImpl")); + HiddenApiBridge.Resources_setImpl(newRes, (ResourcesImpl) XposedHelpers.getObjectField(Resources.getSystem(), "mResourcesImpl")); newRes.initObject(resDir); // Invoke handleInitPackageResources(). @@ -322,11 +239,6 @@ public final class XposedInit { return newRes; } - private static boolean needsToCloseFilesForFork() { - // ed: we always start to do our work after forking finishes - return false; - } - /** * Try to load all modules defined in INSTALLER_DATA_BASE_DIR/conf/modules.list */ @@ -457,34 +369,25 @@ public final class XposedInit { } final Object moduleInstance = moduleClass.newInstance(); - if (XposedBridge.isZygote) { - if (moduleInstance instanceof IXposedHookZygoteInit) { - IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam(); - param.modulePath = apk; - param.startsSystemServer = startsSystemServer; + if (moduleInstance instanceof IXposedHookZygoteInit) { + IXposedHookZygoteInit.StartupParam param = new IXposedHookZygoteInit.StartupParam(); + param.modulePath = apk; + param.startsSystemServer = startsSystemServer; - XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper( - (IXposedHookZygoteInit) moduleInstance, param)); - if (callInitZygote) { - ((IXposedHookZygoteInit) moduleInstance).initZygote(param); - } - } - - if (moduleInstance instanceof IXposedHookLoadPackage) - XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper( - (IXposedHookLoadPackage) moduleInstance, apk)); - - if (moduleInstance instanceof IXposedHookInitPackageResources) - XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper( - (IXposedHookInitPackageResources) moduleInstance, apk)); - } else { - if (moduleInstance instanceof IXposedHookCmdInit) { - IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam(); - param.modulePath = apk; - param.startClassName = startClassName; - ((IXposedHookCmdInit) moduleInstance).initCmdApp(param); + XposedBridge.hookInitZygote(new IXposedHookZygoteInit.Wrapper( + (IXposedHookZygoteInit) moduleInstance, param)); + if (callInitZygote) { + ((IXposedHookZygoteInit) moduleInstance).initZygote(param); } } + + if (moduleInstance instanceof IXposedHookLoadPackage) + XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper( + (IXposedHookLoadPackage) moduleInstance, apk)); + + if (moduleInstance instanceof IXposedHookInitPackageResources) + XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper( + (IXposedHookInitPackageResources) moduleInstance, apk)); } catch (Throwable t) { Log.e(TAG, " Failed to load class " + moduleClassName, t); return false; diff --git a/core/src/main/java/de/robv/android/xposed/callbacks/package-info.java b/core/src/main/java/de/robv/android/xposed/callbacks/package-info.java deleted file mode 100644 index 8ff24d78..00000000 --- a/core/src/main/java/de/robv/android/xposed/callbacks/package-info.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -/** - * Contains the base classes for callbacks. - * - *

For historical reasons, {@link de.robv.android.xposed.XC_MethodHook} and - * {@link de.robv.android.xposed.XC_MethodReplacement} are directly in the - * {@code de.robv.android.xposed} package. - */ -package de.robv.android.xposed.callbacks; - diff --git a/core/src/main/java/de/robv/android/xposed/package-info.java b/core/src/main/java/de/robv/android/xposed/package-info.java deleted file mode 100644 index d3e3020c..00000000 --- a/core/src/main/java/de/robv/android/xposed/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -/** - * Contains the main classes of the Xposed framework. - */ -package de.robv.android.xposed; diff --git a/core/src/main/java/de/robv/android/xposed/services/BinderService.java b/core/src/main/java/de/robv/android/xposed/services/BinderService.java deleted file mode 100644 index 006c983a..00000000 --- a/core/src/main/java/de/robv/android/xposed/services/BinderService.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -package de.robv.android.xposed.services; - -import android.os.IBinder; -import android.os.Parcel; -import android.os.RemoteException; -import android.os.ServiceManager; - -import java.io.IOException; - -/** @hide */ -public final class BinderService extends BaseService { - public static final int TARGET_APP = 0; - public static final int TARGET_SYSTEM = 1; - - /** - * Retrieve the binder service running in the specified context. - * @param target Either {@link #TARGET_APP} or {@link #TARGET_SYSTEM}. - * @return A reference to the service. - * @throws IllegalStateException In case the service doesn't exist (should never happen). - */ - public static BinderService getService(int target) { - if (target < 0 || target > sServices.length) { - throw new IllegalArgumentException("Invalid service target " + target); - } - synchronized (sServices) { - if (sServices[target] == null) { - sServices[target] = new BinderService(target); - } - return sServices[target]; - } - } - - @Override - public boolean checkFileAccess(String filename, int mode) { - ensureAbsolutePath(filename); - - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(INTERFACE_TOKEN); - data.writeString(filename); - data.writeInt(mode); - - try { - mRemote.transact(ACCESS_FILE_TRANSACTION, data, reply, 0); - } catch (RemoteException e) { - data.recycle(); - reply.recycle(); - return false; - } - - reply.readException(); - int result = reply.readInt(); - reply.recycle(); - data.recycle(); - return result == 0; - } - - @Override - public FileResult statFile(String filename) throws IOException { - ensureAbsolutePath(filename); - - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(INTERFACE_TOKEN); - data.writeString(filename); - - try { - mRemote.transact(STAT_FILE_TRANSACTION, data, reply, 0); - } catch (RemoteException e) { - data.recycle(); - reply.recycle(); - throw new IOException(e); - } - - reply.readException(); - int errno = reply.readInt(); - if (errno != 0) - throwCommonIOException(errno, null, filename, " while retrieving attributes for "); - - long size = reply.readLong(); - long time = reply.readLong(); - reply.recycle(); - data.recycle(); - return new FileResult(size, time); - } - - @Override - public byte[] readFile(String filename) throws IOException { - return readFile(filename, 0, 0, 0, 0).content; - } - - @Override - public FileResult readFile(String filename, long previousSize, long previousTime) throws IOException { - return readFile(filename, 0, 0, previousSize, previousTime); - } - - @Override - public FileResult readFile(String filename, int offset, int length, - long previousSize, long previousTime) throws IOException { - ensureAbsolutePath(filename); - - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(INTERFACE_TOKEN); - data.writeString(filename); - data.writeInt(offset); - data.writeInt(length); - data.writeLong(previousSize); - data.writeLong(previousTime); - - try { - mRemote.transact(READ_FILE_TRANSACTION, data, reply, 0); - } catch (RemoteException e) { - data.recycle(); - reply.recycle(); - throw new IOException(e); - } - - reply.readException(); - int errno = reply.readInt(); - String errorMsg = reply.readString(); - long size = reply.readLong(); - long time = reply.readLong(); - byte[] content = reply.createByteArray(); - reply.recycle(); - data.recycle(); - - switch (errno) { - case 0: - return new FileResult(content, size, time); - case 22: // EINVAL - if (errorMsg != null) { - IllegalArgumentException iae = new IllegalArgumentException(errorMsg); - if (offset == 0 && length == 0) - throw new IOException(iae); - else - throw iae; - } else { - throw new IllegalArgumentException("Offset " + offset + " / Length " + length - + " is out of range for " + filename + " with size " + size); - } - default: - throwCommonIOException(errno, errorMsg, filename, " while reading "); - throw new IllegalStateException(); // not reached - } - } - - - // ---------------------------------------------------------------------------- - private static final String INTERFACE_TOKEN = "de.robv.android.xposed.IXposedService"; - - private static final int ACCESS_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 2; - private static final int STAT_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 3; - private static final int READ_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 4; - - private static final String[] SERVICE_NAMES = { "user.xposed.app", "user.xposed.system" }; - private static final BinderService[] sServices = new BinderService[2]; - private final IBinder mRemote; - - private BinderService(int target) { - IBinder binder = ServiceManager.getService(SERVICE_NAMES[target]); - if (binder == null) - throw new IllegalStateException("Service " + SERVICE_NAMES[target] + " does not exist"); - this.mRemote = binder; - } -} diff --git a/core/src/main/java/de/robv/android/xposed/services/ZygoteService.java b/core/src/main/java/de/robv/android/xposed/services/ZygoteService.java deleted file mode 100644 index 8d1a76f6..00000000 --- a/core/src/main/java/de/robv/android/xposed/services/ZygoteService.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -package de.robv.android.xposed.services; - -import java.io.IOException; -import java.util.Arrays; - -/** @hide */ -@SuppressWarnings("JniMissingFunction") -public final class ZygoteService extends BaseService { - @Override - public native boolean checkFileAccess(String filename, int mode); - - @Override - public native FileResult statFile(String filename) throws IOException; - - @Override - public native byte[] readFile(String filename) throws IOException; - - @Override - // Just for completeness, we don't expect this to be called often in Zygote. - public FileResult readFile(String filename, long previousSize, long previousTime) throws IOException { - FileResult stat = statFile(filename); - if (previousSize == stat.size && previousTime == stat.mtime) - return stat; - return new FileResult(readFile(filename), stat.size, stat.mtime); - } - - @Override - // Just for completeness, we don't expect this to be called often in Zygote. - public FileResult readFile(String filename, int offset, int length, long previousSize, long previousTime) throws IOException { - FileResult stat = statFile(filename); - if (previousSize == stat.size && previousTime == stat.mtime) - return stat; - - // Shortcut for the simple case - if (offset <= 0 && length <= 0) - return new FileResult(readFile(filename), stat.size, stat.mtime); - - // Check range - if (offset > 0 && offset >= stat.size) { - throw new IllegalArgumentException("offset " + offset + " >= size " + stat.size + " for " + filename); - } else if (offset < 0) { - offset = 0; - } - - if (length > 0 && (offset + length) > stat.size) { - throw new IllegalArgumentException("offset " + offset + " + length " + length + " > size " + stat.size + " for " + filename); - } else if (length <= 0) { - length = (int) (stat.size - offset); - } - - byte[] content = readFile(filename); - return new FileResult(Arrays.copyOfRange(content, offset, offset + length), stat.size, stat.mtime); - } -} diff --git a/core/src/main/java/de/robv/android/xposed/services/package-info.java b/core/src/main/java/de/robv/android/xposed/services/package-info.java deleted file mode 100644 index ba5657ed..00000000 --- a/core/src/main/java/de/robv/android/xposed/services/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of LSPosed. - * - * LSPosed is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LSPosed is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LSPosed. If not, see . - * - * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors - */ - -/** - * Contains file access services provided by the Xposed framework. - */ -package de.robv.android.xposed.services; diff --git a/core/src/main/java/de/robv/android/xposed/annotation/ApiSensitive.java b/core/src/main/java/io/github/lsposed/lspd/annotation/ApiSensitive.java similarity index 96% rename from core/src/main/java/de/robv/android/xposed/annotation/ApiSensitive.java rename to core/src/main/java/io/github/lsposed/lspd/annotation/ApiSensitive.java index 69715511..a078c8b0 100644 --- a/core/src/main/java/de/robv/android/xposed/annotation/ApiSensitive.java +++ b/core/src/main/java/io/github/lsposed/lspd/annotation/ApiSensitive.java @@ -18,7 +18,7 @@ * Copyright (C) 2021 LSPosed Contributors */ -package de.robv.android.xposed.annotation; +package io.github.lsposed.lspd.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/core/src/main/java/de/robv/android/xposed/annotation/Level.java b/core/src/main/java/io/github/lsposed/lspd/annotation/Level.java similarity index 95% rename from core/src/main/java/de/robv/android/xposed/annotation/Level.java rename to core/src/main/java/io/github/lsposed/lspd/annotation/Level.java index 95ec610c..910084d8 100644 --- a/core/src/main/java/de/robv/android/xposed/annotation/Level.java +++ b/core/src/main/java/io/github/lsposed/lspd/annotation/Level.java @@ -18,7 +18,7 @@ * Copyright (C) 2021 LSPosed Contributors */ -package de.robv.android.xposed.annotation; +package io.github.lsposed.lspd.annotation; public enum Level { LOW, MIDDLE, HIGH; diff --git a/core/src/main/java/io/github/lsposed/lspd/deopt/InlinedMethodCallers.java b/core/src/main/java/io/github/lsposed/lspd/deopt/InlinedMethodCallers.java index fae54290..07a53d7f 100644 --- a/core/src/main/java/io/github/lsposed/lspd/deopt/InlinedMethodCallers.java +++ b/core/src/main/java/io/github/lsposed/lspd/deopt/InlinedMethodCallers.java @@ -22,8 +22,8 @@ package io.github.lsposed.lspd.deopt; import java.util.HashMap; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; /** * Providing a whitelist of methods which are the callers of the target methods we want to hook. diff --git a/core/src/main/java/io/github/lsposed/lspd/proxy/BaseRouter.java b/core/src/main/java/io/github/lsposed/lspd/proxy/BaseRouter.java index f6815bd9..e4e5060c 100644 --- a/core/src/main/java/io/github/lsposed/lspd/proxy/BaseRouter.java +++ b/core/src/main/java/io/github/lsposed/lspd/proxy/BaseRouter.java @@ -37,8 +37,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.XposedInit; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; public abstract class BaseRouter implements Router { @@ -60,7 +60,7 @@ public abstract class BaseRouter implements Router { return; } startBootstrapHook(isSystem, appDataDir); - XposedInit.initForZygote(isSystem); + XposedInit.initForZygote(); } catch (Throwable t) { Utils.logE("error during Xposed initialization", t); } diff --git a/core/src/main/java/io/github/lsposed/lspd/proxy/NormalProxy.java b/core/src/main/java/io/github/lsposed/lspd/proxy/NormalProxy.java index f2b1d72a..c49a7007 100644 --- a/core/src/main/java/io/github/lsposed/lspd/proxy/NormalProxy.java +++ b/core/src/main/java/io/github/lsposed/lspd/proxy/NormalProxy.java @@ -28,8 +28,6 @@ import io.github.lsposed.lspd.deopt.PrebuiltMethodsDeopter; import io.github.lsposed.lspd.nativebridge.ModuleLogger; import io.github.lsposed.lspd.util.Utils; -import de.robv.android.xposed.SELinuxHelper; - import static io.github.lsposed.lspd.config.LSPApplicationServiceClient.serviceClient; public class NormalProxy extends BaseProxy { @@ -51,7 +49,6 @@ public class NormalProxy extends BaseProxy { private void forkPostCommon(boolean isSystem, String appDataDir, String niceName) { // init logger ModuleLogger.initLogger(serviceClient.getModuleLogger()); - SELinuxHelper.initOnce(); mRouter.initResourcesHook(); mRouter.prepare(isSystem); PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote diff --git a/core/src/main/java/io/github/lsposed/lspd/util/ClassLoaderUtils.java b/core/src/main/java/io/github/lsposed/lspd/util/ClassLoaderUtils.java index 0beb0ea4..503717e0 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/ClassLoaderUtils.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/ClassLoaderUtils.java @@ -35,8 +35,8 @@ import dalvik.system.PathClassLoader; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; @ApiSensitive(Level.LOW) public class ClassLoaderUtils { diff --git a/core/src/main/java/io/github/lsposed/lspd/util/ClassUtils.java b/core/src/main/java/io/github/lsposed/lspd/util/ClassUtils.java index f258a7ba..d36a0c6b 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/ClassUtils.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/ClassUtils.java @@ -27,8 +27,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import de.robv.android.xposed.XposedHelpers; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; public class ClassUtils { diff --git a/core/src/main/java/io/github/lsposed/lspd/util/DexUtils.java b/core/src/main/java/io/github/lsposed/lspd/util/DexUtils.java index 99878dbc..1a68853c 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/DexUtils.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/DexUtils.java @@ -28,8 +28,8 @@ import java.lang.reflect.Field; import dalvik.system.BaseDexClassLoader; import dalvik.system.DexClassLoader; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; /** * For 6.0 only. diff --git a/core/src/main/java/io/github/lsposed/lspd/util/ProcessUtils.java b/core/src/main/java/io/github/lsposed/lspd/util/ProcessUtils.java index 9a1b3892..37535b29 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/ProcessUtils.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/ProcessUtils.java @@ -28,8 +28,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; @ApiSensitive(Level.LOW) public class ProcessUtils { diff --git a/core/src/main/java/io/github/lsposed/lspd/util/Unsafe.java b/core/src/main/java/io/github/lsposed/lspd/util/Unsafe.java index 76b44141..5e0acfaf 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/Unsafe.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/Unsafe.java @@ -25,8 +25,8 @@ import android.util.Log; import java.lang.reflect.Field; import java.lang.reflect.Method; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; @ApiSensitive(Level.LOW) public final class Unsafe { diff --git a/core/src/main/java/io/github/lsposed/lspd/util/Utils.java b/core/src/main/java/io/github/lsposed/lspd/util/Utils.java index d5145bee..d66374ba 100644 --- a/core/src/main/java/io/github/lsposed/lspd/util/Utils.java +++ b/core/src/main/java/io/github/lsposed/lspd/util/Utils.java @@ -25,8 +25,8 @@ import android.util.Log; import io.github.lsposed.lspd.BuildConfig; import de.robv.android.xposed.XposedHelpers; -import de.robv.android.xposed.annotation.ApiSensitive; -import de.robv.android.xposed.annotation.Level; +import io.github.lsposed.lspd.annotation.ApiSensitive; +import io.github.lsposed.lspd.annotation.Level; public class Utils { diff --git a/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java b/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java index 6cc3ddf2..50e2c656 100644 --- a/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java +++ b/hiddenapi-bridge/src/main/java/hidden/HiddenApiBridge.java @@ -20,6 +20,8 @@ package hidden; import android.content.res.AssetManager; +import android.content.res.Resources; +import android.content.res.ResourcesImpl; import android.os.Binder; import android.os.IBinder; @@ -31,4 +33,8 @@ public class HiddenApiBridge { public static IBinder Binder_allowBlocking(IBinder binder) { return Binder.allowBlocking(binder); } + + public static void Resources_setImpl(Resources resources, ResourcesImpl impl) { + resources.setImpl(impl); + } } diff --git a/hiddenapi-stubs/src/main/java/android/content/res/Resources.java b/hiddenapi-stubs/src/main/java/android/content/res/Resources.java index 236bef8b..3e00aa9f 100644 --- a/hiddenapi-stubs/src/main/java/android/content/res/Resources.java +++ b/hiddenapi-stubs/src/main/java/android/content/res/Resources.java @@ -10,4 +10,9 @@ public class Resources { public Resources(ClassLoader classLoader) { throw new UnsupportedOperationException("STUB"); } + + public void setImpl(ResourcesImpl impl) { + throw new UnsupportedOperationException("STUB"); + } + } diff --git a/hiddenapi-stubs/src/main/java/android/os/SELinux.java b/hiddenapi-stubs/src/main/java/android/os/SELinux.java deleted file mode 100644 index b257df4b..00000000 --- a/hiddenapi-stubs/src/main/java/android/os/SELinux.java +++ /dev/null @@ -1,15 +0,0 @@ -package android.os; - -public class SELinux { - public static final String getContext() { - throw new UnsupportedOperationException("STUB"); - } - - public static final boolean isSELinuxEnabled() { - throw new UnsupportedOperationException("STUB"); - } - - public static final boolean isSELinuxEnforced() { - throw new UnsupportedOperationException("STUB"); - } -}