diff --git a/README.md b/README.md index 393fa18f..f744c057 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,22 @@ -# EdXposed +# EdXposed Framework -Latest builds: [![Build status](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master) +[![Latest builds](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master) [![中文说明文档](art/README_CN.png)](README_CN.md) -A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework. +## Introduction -## Supported versions +A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework, supports Android 8.0 ~ **10**. -- Android Oreo (8.x) -- Android Pie (9.0) -- Android 10 +> Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo. As all changes are done in the memory, you just need to deactivate the module and reboot to get your original system back. There are many other advantages, but here is just one more: Multiple modules can do changes to the same part of the system or app. With modified APKs, you to decide for one. No way to combine them, unless the author builds multiple APKs with different combinations. + +## Supported Versions + +- Android Q (10)[sdk29] +- Android Pie (9)[sdk28] +- Android Oreo (8.x)[sdk26/27] For Android Nougat (7.x) and lower, please use the original Xposed Framework. -## Build requirements +## Build Requirements Same as [Riru-Core's](https://github.com/RikkaApps/Riru/blob/master/README.md#build-requirements) and zip binaries can be downloaded from [here](http://gnuwin32.sourceforge.net/packages/zip.htm). @@ -25,41 +29,63 @@ and zip binaries can be downloaded from [here](http://gnuwin32.sourceforge.net/p ## Install -1. Install Magisk v19.0+ (for latest EdXposed or Huawei devices, use our custom Magisk: Change Magisk update channel to [this](http://edxp.meowcat.org/repo/version.json)). +1. Install Magisk v19+ (for Huawei/Honor or OnePlus 7T/7TPro device, need Magisk v20.2+) 2. Install [Riru-Core](https://github.com/RikkaApps/Riru/releases) v19+ from Magisk repo. -3. Download [EdXposed](https://github.com/solohsu/EdXposed/releases) and install it in Magisk Manager or recovery mode. +3. [Download](#download) and install EdXposed in Magisk Manager or recovery mode. 4. Install [companion application](#companion-applications). 4. Reboot. 5. Have fun! :) -## Companion applications +## Download + +Edxposed has three different builds + +- Stable:Stable version after passing the test, suitable for general users, update slowly. +***Download Stable version in Magisk Manager's [Downloads] tab*** + +- Alpha: Test version with multiple commits. +***Download Alpha version in [[Github Releases](https://github.com/ElderDrivers/EdXposed/releases)]*** + +- Canary: Debug version. Automatically build by CI. +***Download Canary version in [[EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)]*** + +## Companion Applications + +> Both Xposed Installer and EdXposed Installer are deprecated. Support will be stopped for later versions. Please use [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager) - For v0.2.9.5 and before: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller). - For v0.2.9.6 and v0.2.9.7: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller) + [EdXp Manager](https://github.com/solohsu/EdXpManager)(optional). - For v0.2.9.8 and later: [EdXposed Installer](https://github.com/solohsu/XposedInstaller) and [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager). - For the latest version, we recommend to use [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager). -## Useful links +## Useful Links - [List of Xposed Modules For Android Pie Working With EdXposed](https://forum.xda-developers.com/xposed/list-xposed-modules-android-pie-ed-t3892768) (thanks to Uraniam9 @ xda-developers) -## Known issues +## Known Issues -- May not be compatible with all ART devices. -- File access services are not implemented yet, now EdXp simply uses magiskpolicy to enable needed SELinux policies. -- Dynamic modules not work, caused by SELinux. +See [Wiki: Known issues or bugs](https://github.com/ElderDrivers/EdXposed/wiki/Known-issues-or-bugs) -## Get help +## Get Help -- GitHub issues: [Issues](https://github.com/solohsu/EdXposed/issues/) +- GitHub issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/) -Notice(for Chinese): 鉴于部分用户提交的Issues质量过低,对于中文用户反馈,请先阅读[EdXposed错误提交说明_cn](https://raw.githubusercontent.com/ElderDrivers/Repository-Website/gh-pages/repo/EdXposedIssuesReport_cn.txt)(不看说明提交的Issue会有很大可能被close) +- Notice(for Chinese): In view of the low quality of issues submitted, please read the Chinese user report first[EdXposedIssuesReport_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(If you don't read the instructions, the submitted issue is likely to be closed) -## Community +## For Developers + +Developers are welcomed to write Xposed modules with hooks based on EdXposed Framework. Module written based on EdXposed framework is fully compatible with the original Xposed Framework, so contrary a Xposed Framework-based module will work well with the EdXposed framework too. + +- [Xposed Framework API](https://api.xposed.info/) + +We use the module repository of the original Xposed, so you simply upload the module to repository, then you can download your module in EdXposed. + +- [Xposed Module Repository](https://repo.xposed.info/) + +## Community Discussion - QQ Group: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f) -- Telegram: [Code_of_MeowCat](http://t.me/Code_of_MeowCat) -- Discord (not recommended): [Code_of_MeowCat](https://discord.gg/Hag6gNh) +- Telegram: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat) Notice: These community group don't accept any bug report, please use [Get help](#get-help) to report. diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 00000000..dd449fc2 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,96 @@ +# EdXposed Framework + +[![最新构建](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master) [![English](art/README_EN.png)](README.md) + +## Introduction + +基于 Riru 的 ART hook 框架 (最初用于 Android Pie) ,提供与原版 Xposed 相同的 API, 使用 YAHFA (或 SandHook) 进行 hook, supports Android 8.0 ~ **10**. + +> Xposed 框架是一套开放源代码的、在Android高权限模式下运行的框架服务,可以在不修改APK文件的情况下修改程序的运行,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作 + +## 支持的版本 + +- Android Oreo (8.x, sdk26/27) +- Android Pie (9, sdk28) +- Android Q (10, sdk29) + +如果你使用 Android Nougat (7.x) 或更低版本, 请使用原版的 Xposed 框架 + +## 编译需求 + +见 [Riru-Core 的编译需求](https://github.com/RikkaApps/Riru/blob/master/README.md#build-requirements) +zip 可执行文件可以在 [这里](http://gnuwin32.sourceforge.net/packages/zip.htm) 下载 + +## 编译和使用 + +1. 执行 `:edxp-core:[zip|push][Yahfa|Sandhook]Release` 来构建对应分支的可刷入的 zip 文件 +2. 在 `edxp-core/release/` 中找到可刷入的 zip 文件 +3. 经由 Magisk Manager 或在恢复模式(Recovery)中刷入 + +## 安装 + +1. 安装 Magisk v19+ (对于 华为 / 荣耀 或 一加 7T / 7TPro 设备, 需要 Magisk v20.2+) +2. 在 Magisk 仓库中安装 [Riru-Core](https://github.com/RikkaApps/Riru/releases) v19 或更高版本. +3. [下载](#下载)并在恢复模式(Recovery)或经由 Magisk Manager 安装 EdXposed. +4. 安装 [框架管理应用](#框架管理应用). +4. 重启手机. +5. 完成 :) + +## 下载 + +Edxposed 拥有三个不同的版本 + +- Stable:经过测试的稳定版, 适合一般用户,更新缓慢. +***在 [Magisk Manager] 中的 [下载] 页中下载 Stable 版本*** + +- Alpha: 多次提交更新的测试版. +***在 [[Github Releases](https://github.com/ElderDrivers/EdXposed/releases)] 中下载 Alpha 版本*** + +- Canary: 由 CI 自动生成的测试版. +***在 [[EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)] 中下载 Canary 版本*** + +## 框架管理应用 + +> Xposed Installer 和 EdXposed Installer 均已停更,后续版本将取消支持,请使用 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager) + +- 对于 v0.2.9.5 或更低版本: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller). +- 对于 v0.2.9.6 和 v0.2.9.7: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller) + [EdXp Manager](https://github.com/solohsu/EdXpManager)(optional). +- 对于 v0.2.9.8 或更高版本: [EdXposed Installer](https://github.com/solohsu/XposedInstaller) 或者 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager). +- 对于最新版,我们建议使用 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager). + +## 外部链接 + +- [List of Xposed Modules For Android Pie Working With EdXposed](https://forum.xda-developers.com/xposed/list-xposed-modules-android-pie-ed-t3892768) (感谢 Uraniam9 @ xda-developers) + +## 已知问题 + +见 [Wiki: 已知问题和漏洞](https://github.com/ElderDrivers/EdXposed/wiki/已知问题和漏洞) + +## 获取帮助 + +- GitHub issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/) + +- 注意: 鉴于部分用户提交的Issues质量过低,对于中文用户反馈,请先阅读[EdXposed错误提交说明_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(不看说明提交的Issue会有很大可能被close) + +## 社区交流 + +- QQ 群组: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f) +- Telegram 电报: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat) + +注意: 这些社区群组不接收问题反馈, 请使用 [获取帮助](#获取帮助) 进行反馈. + +## 贡献 + +- 显然,框架还不够稳定,欢迎使用PR贡献代码. :) +- 如果你愿意,可以[请我喝杯咖啡](https://www.paypal.me/givin2u). + +## 鸣谢 + +- [YAHFA](https://github.com/rk700/YAHFA): ART hook 核心框架 +- [Magisk](https://github.com/topjohnwu/Magisk/): 让一切成为可能 +- [Riru](https://github.com/RikkaApps/Riru): 提供一种将代码注入 zygote 进程的方法 +- [XposedBridge](https://github.com/rovo89/XposedBridge): 原版 xposed 框架的 API +- [dexmaker](https://github.com/linkedin/dexmaker) 和 [dalvikdx](https://github.com/JakeWharton/dalvik-dx): 动态生成 YAHFA hook 类 +- [Whale](https://github.com/asLody/whale): 用于 hook 内联方法 +- [SandHook](https://github.com/ganyao114/SandHook/): SandHook 分支的 ART hooking 框架 + diff --git a/appveyor.yml b/appveyor.yml index ff7e8cb3..ac454144 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '0.4.6.0_beta({build})' +version: '0.4.6.3 ({build})' environment: ANDROID_HOME: C:\android-sdk-windows diff --git a/art/README_CN.png b/art/README_CN.png new file mode 100644 index 00000000..764bc884 Binary files /dev/null and b/art/README_CN.png differ diff --git a/art/README_EN.png b/art/README_EN.png new file mode 100644 index 00000000..ba77ec93 Binary files /dev/null and b/art/README_EN.png differ diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/HandleBindApp.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/HandleBindApp.java index bf27a3a9..80262e7b 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/HandleBindApp.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/HandleBindApp.java @@ -8,7 +8,6 @@ import android.content.res.CompatibilityInfo; import android.content.res.XResources; import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; import com.elderdrivers.riru.edxp.util.Hookers; import com.elderdrivers.riru.edxp.util.Utils; @@ -22,9 +21,6 @@ public class HandleBindApp extends XC_MethodHook { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - if (XposedBlackListHooker.shouldDisableHooks("")) { - return; - } try { Hookers.logD("ActivityThread#handleBindApplication() starts"); ActivityThread activityThread = (ActivityThread) param.thisObject; @@ -36,10 +32,6 @@ public class HandleBindApp extends XC_MethodHook { Utils.logD("processName=" + ConfigManager.appProcessName + ", packageName=" + reportedPackageName + ", appDataDir=" + ConfigManager.appDataDir); - if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) { - return; - } - ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName"); if (instrumentationName != null) { Hookers.logD("Instrumentation detected, disabling framework for"); diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkCstr.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkCstr.java index 3464f4c2..4ec4baf2 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkCstr.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkCstr.java @@ -5,7 +5,6 @@ import android.app.LoadedApk; import android.content.res.XResources; import android.util.Log; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; import com.elderdrivers.riru.edxp.util.Hookers; import de.robv.android.xposed.XC_MethodHook; @@ -18,10 +17,6 @@ public class LoadedApkCstr extends XC_MethodHook { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { - if (XposedBlackListHooker.shouldDisableHooks("")) { - return; - } - Hookers.logD("LoadedApk# starts"); try { @@ -32,10 +27,6 @@ public class LoadedApkCstr extends XC_MethodHook { XResources.setPackageNameForResDir(packageName, loadedApk.getResDir()); - if (XposedBlackListHooker.shouldDisableHooks(packageName)) { - return; - } - if (packageName.equals("android")) { Hookers.logD("LoadedApk# is android, skip: " + mAppDir); return; diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkGetCL.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkGetCL.java index eb3bd523..8e71b7c4 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkGetCL.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/_hooker/impl/LoadedApkGetCL.java @@ -2,8 +2,8 @@ package com.elderdrivers.riru.edxp._hooker.impl; import android.app.LoadedApk; +import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.hooker.SliceProviderFix; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; import com.elderdrivers.riru.edxp.hooker.XposedInstallerHooker; import com.elderdrivers.riru.edxp.util.Hookers; @@ -12,10 +12,7 @@ import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; -import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME; import static com.elderdrivers.riru.edxp.hooker.SliceProviderFix.SYSTEMUI_PACKAGE_NAME; -import static com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; - public class LoadedApkGetCL extends XC_MethodHook { @@ -38,10 +35,6 @@ public class LoadedApkGetCL extends XC_MethodHook { try { - if (XposedBlackListHooker.shouldDisableHooks("")) { - return; - } - Hookers.logD("LoadedApk#getClassLoader starts"); LoadedApk loadedApk = (LoadedApk) param.thisObject; @@ -67,12 +60,9 @@ public class LoadedApkGetCL extends XC_MethodHook { lpparam.isFirstApplication = this.isFirstApplication; XC_LoadPackage.callAll(lpparam); - if (this.packageName.equals(INSTALLER_PACKAGE_NAME)) { + if (this.packageName.equals(ConfigManager.getInstallerPackageName())) { XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader); } - if (this.packageName.equals(BLACK_LIST_PACKAGE_NAME)) { - XposedBlackListHooker.hook(lpparam.classLoader); - } if (this.packageName.equals(SYSTEMUI_PACKAGE_NAME)) { SliceProviderFix.hook(); } diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java index a05c399f..12474f64 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/BaseEdxpConfig.java @@ -1,17 +1,35 @@ package com.elderdrivers.riru.edxp.config; -import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker; +import android.text.TextUtils; public class BaseEdxpConfig implements EdxpConfig { @Override - public String getInstallerBaseDir() { - return InstallerChooser.INSTALLER_DATA_BASE_DIR; + public String getInstallerConfigPath(String suffix) { + return ConfigManager.getInstallerConfigPath(suffix != null ? suffix : ""); } @Override - public String getBlackListModulePackageName() { - return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; + public String getDataPathPrefix() { + return ConfigManager.getDataPathPrefix(); + } + + @Override + public String getInstallerPackageName() { + return ConfigManager.getInstallerPackageName(); + } + + @Override + public String getXposedPropPath() { + return ConfigManager.getXposedPropPath(); + } + @Override + public String getLibSandHookName() { + return ConfigManager.getLibSandHookName(); + } + @Override + public String getLibWhaleName() { + return ConfigManager.getLibWhaleName(); } @Override @@ -24,6 +42,11 @@ public class BaseEdxpConfig implements EdxpConfig { return ConfigManager.isResourcesHookEnabled(); } + @Override + public boolean isNoModuleLogEnabled() { + return ConfigManager.isNoModuleLogEnabled(); + } + @Override public boolean isBlackWhiteListMode() { return ConfigManager.isBlackWhiteListEnabled(); diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java index cf579877..e237c276 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java @@ -4,15 +4,12 @@ import java.util.HashMap; import de.robv.android.xposed.SELinuxHelper; -import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_DATA_BASE_DIR; - public class ConfigManager { public static String appDataDir = ""; public static String niceName = ""; public static String appProcessName = ""; - private static final String COMPAT_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/compatlist/"; private static final HashMap compatModeCache = new HashMap<>(); public static boolean shouldUseCompatMode(String packageName) { @@ -21,7 +18,7 @@ public class ConfigManager { && (result = compatModeCache.get(packageName)) != null) { return result; } - result = isFileExists(COMPAT_LIST_PATH + packageName); + result = isFileExists(getInstallerConfigPath("compatlist/" + packageName)); compatModeCache.put(packageName, result); return result; } @@ -34,11 +31,23 @@ public class ConfigManager { public static native boolean isDynamicModulesEnabled(); + public static native boolean isNoModuleLogEnabled(); + public static native boolean isResourcesHookEnabled(); public static native boolean isDeoptBootImageEnabled(); public static native String getInstallerPackageName(); + public static native String getXposedPropPath(); + + public static native String getLibSandHookName(); + + public static native String getLibWhaleName(); + + public static native String getInstallerConfigPath(String suffix); + + public static native String getDataPathPrefix(); + public static native boolean isAppNeedHook(String appDataDir); } diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java deleted file mode 100644 index 9e829296..00000000 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.elderdrivers.riru.edxp.config; - -import android.annotation.SuppressLint; -import android.os.Build; - -import com.elderdrivers.riru.edxp.util.Utils; - -import java.util.concurrent.atomic.AtomicBoolean; - -import de.robv.android.xposed.SELinuxHelper; -import de.robv.android.xposed.services.BaseService; - -public class InstallerChooser { - - private static final AtomicBoolean hasSet = new AtomicBoolean(false); - @SuppressLint("SdCardPath") - private static final String DATA_DIR_PATH_PREFIX = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? "/data/user_de/0/" : "/data/user/0/"; - - - public static final String PRIMARY_INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager"; - public static final String SECONDARY_INSTALLER_PACKAGE_NAME = "org.meowcat.edxposed.manager"; - public static final String LEGACY_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer"; - - public static String INSTALLER_PACKAGE_NAME; - public static String INSTALLER_DATA_BASE_DIR; - - public static void setInstallerPackageName(String packageName) { - INSTALLER_PACKAGE_NAME = packageName; - INSTALLER_DATA_BASE_DIR = DATA_DIR_PATH_PREFIX + INSTALLER_PACKAGE_NAME + "/"; - } - - public static void setup() { - if (!hasSet.compareAndSet(false, true)) { - // init once - return; - } - String dataBaseDir; - if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + PRIMARY_INSTALLER_PACKAGE_NAME + "/")) { - INSTALLER_PACKAGE_NAME = PRIMARY_INSTALLER_PACKAGE_NAME; - INSTALLER_DATA_BASE_DIR = dataBaseDir; - Utils.logI("using " + PRIMARY_INSTALLER_PACKAGE_NAME + "as installer app"); - return; - } - if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + SECONDARY_INSTALLER_PACKAGE_NAME + "/")) { - INSTALLER_PACKAGE_NAME = SECONDARY_INSTALLER_PACKAGE_NAME; - INSTALLER_DATA_BASE_DIR = dataBaseDir; - Utils.logI("using " + SECONDARY_INSTALLER_PACKAGE_NAME + "as installer app"); - return; - } - if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + LEGACY_INSTALLER_PACKAGE_NAME + "/")) { - INSTALLER_PACKAGE_NAME = LEGACY_INSTALLER_PACKAGE_NAME; - INSTALLER_DATA_BASE_DIR = dataBaseDir; - Utils.logI("using " + LEGACY_INSTALLER_PACKAGE_NAME + "as installer app"); - return; - } - Utils.logE("no supported installer app found"); - } - - /** - * For some reason checkFileExists(dirPath) is not reliable when forkSystemServerPre - */ - private static boolean checkDataDirValid(String dirPath) { - BaseService fileService = SELinuxHelper.getAppDataFileService(); - return fileService.checkFileExists(dirPath + "code_cache") - || fileService.checkFileExists(dirPath + "cache"); - } -} diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedBlackListHooker.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedBlackListHooker.java deleted file mode 100644 index c5e10ab6..00000000 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedBlackListHooker.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.elderdrivers.riru.edxp.hooker; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.ContextWrapper; -import android.os.Build; - -import com.elderdrivers.riru.edxp.util.Utils; - -import java.io.File; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import de.robv.android.xposed.XC_MethodHook; -import de.robv.android.xposed.XSharedPreferences; -import de.robv.android.xposed.XposedBridge; -import de.robv.android.xposed.XposedHelpers; - -import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME; -import static com.elderdrivers.riru.edxp.util.FileUtils.IS_USING_PROTECTED_STORAGE; - -public class XposedBlackListHooker { - - public static final String BLACK_LIST_PACKAGE_NAME = "com.flarejune.xposedblacklist"; - private static final String BLACK_LIST_PREF_NAME = "list"; - private static final String PREF_KEY_BLACK_LIST = "blackList"; - public static final String PREF_FILE_PATH = (IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data") - + BLACK_LIST_PACKAGE_NAME + "/shared_prefs/" + BLACK_LIST_PREF_NAME + ".xml"; - private static final XSharedPreferences PREFERENCES = new XSharedPreferences(new File(PREF_FILE_PATH)); - // always white list. empty string is to make sure blackList does not contain empty packageName - private static final List WHITE_LIST = Arrays.asList(INSTALLER_PACKAGE_NAME, BLACK_LIST_PACKAGE_NAME, ""); - - static { - try { - PREFERENCES.makeWorldReadable(); - } catch (Throwable throwable) { - Utils.logE("error making pref worldReadable", throwable); - } - } - - public static boolean shouldDisableHooks(String packageName) { - return XposedBridge.disableHooks || getBlackList().contains(packageName); - } - - public static Set getBlackList() { - try { - PREFERENCES.reload(); - Set result = PREFERENCES.getStringSet(PREF_KEY_BLACK_LIST, new HashSet()); - if (result != null) result.removeAll(WHITE_LIST); - return result; - } catch (Throwable throwable) { - Utils.logE("error when reading black list", throwable); - return new HashSet<>(); - } - } - - public static void hook(ClassLoader classLoader) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - return; - } - try { - XposedHelpers.findAndHookMethod(ContextWrapper.class, "getSharedPreferences", String.class, int.class, new XC_MethodHook() { - @TargetApi(Build.VERSION_CODES.N) - @Override - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - try { - String prefName = (String) param.args[0]; - if (!prefName.equals(BLACK_LIST_PREF_NAME)) { - return; - } - Activity activity = (Activity) param.thisObject; - Context context = activity.createDeviceProtectedStorageContext(); - context.moveSharedPreferencesFrom(activity, prefName); - param.setResult(context.getSharedPreferences(prefName, (int) param.args[1])); - } catch (Throwable throwable) { - Utils.logE("error hooking Xposed BlackList", throwable); - } - } - }); - } catch (Throwable throwable) { - Utils.logE("error hooking Xposed BlackList", throwable); - } - } -} diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedInstallerHooker.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedInstallerHooker.java index 57504b77..719b757c 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedInstallerHooker.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/hooker/XposedInstallerHooker.java @@ -1,5 +1,6 @@ package com.elderdrivers.riru.edxp.hooker; +import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.util.Utils; import java.io.File; @@ -11,10 +12,10 @@ import de.robv.android.xposed.XC_MethodReplacement; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; -import static com.elderdrivers.riru.edxp.config.InstallerChooser.LEGACY_INSTALLER_PACKAGE_NAME; - public class XposedInstallerHooker { + private static final String LEGACY_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer"; + public static void hookXposedInstaller(ClassLoader classLoader) { try { final String xposedAppClass = LEGACY_INSTALLER_PACKAGE_NAME + ".XposedApp"; @@ -29,12 +30,15 @@ public class XposedInstallerHooker { Utils.logD("before reloadXposedProp..."); final String propFieldName = "mXposedProp"; final Object thisObject = param.thisObject; + if (thisObject == null) { + return; + } if (XposedHelpers.getObjectField(thisObject, propFieldName) != null) { param.setResult(null); Utils.logD("reloadXposedProp already done, skip..."); return; } - File file = new File("/system/framework/edconfig.jar"); + File file = new File(ConfigManager.getXposedPropPath()); FileInputStream is = null; try { is = new FileInputStream(file); diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java index 98ba85cc..e4758e99 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/BaseRouter.java @@ -145,7 +145,7 @@ public abstract class BaseRouter implements Router { XposedHelpers.findAndHookMethod(OnePlusWorkAroundHooker.className, classLoader, OnePlusWorkAroundHooker.methodName, int.class, String.class, new OneplusWorkaround()); - } catch (Throwable throwable) { + } catch (Throwable ignored) { } } else { HookMain.doHookDefault( diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/NormalProxy.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/NormalProxy.java index f8510561..54b0d052 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/NormalProxy.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/proxy/NormalProxy.java @@ -3,6 +3,8 @@ package com.elderdrivers.riru.edxp.proxy; import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter; +import de.robv.android.xposed.SELinuxHelper; + import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; public class NormalProxy extends BaseProxy { @@ -18,6 +20,7 @@ public class NormalProxy extends BaseProxy { String appDataDir) { // mainly for secondary zygote mRouter.onForkStart(); + SELinuxHelper.initOnce(); mRouter.initResourcesHook(); // call this to ensure the flag is set to false ASAP mRouter.prepare(false); @@ -36,6 +39,7 @@ public class NormalProxy extends BaseProxy { public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { mRouter.onForkStart(); + SELinuxHelper.initOnce(); mRouter.initResourcesHook(); // set startsSystemServer flag used when loadModules mRouter.prepare(true); diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java index 09e429b3..75aa4cbc 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java @@ -64,9 +64,9 @@ public class ClassLoaderUtils { } } - public static ClassLoader createComposeClassLoader(ClassLoader appClassLoader) { + public static ClassLoader createProxyClassLoader(ClassLoader appClassLoader) { ClassLoader current = ClassLoaderUtils.class.getClassLoader(); - return appClassLoader == null ? current : new ComposeClassLoader(appClassLoader, current); + return appClassLoader == null ? current : new ProxyClassLoader(appClassLoader, current); } public static List getAppClassLoader() { diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ComposeClassLoader.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ComposeClassLoader.java deleted file mode 100644 index 1409b40b..00000000 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ComposeClassLoader.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.elderdrivers.riru.edxp.util; - -/** - * Created by weishu on 17/11/30. - */ - -public class ComposeClassLoader extends ClassLoader { - - private final ClassLoader mAppClassLoader; - - public ComposeClassLoader(ClassLoader parent, ClassLoader appClassLoader) { - super(parent); - mAppClassLoader = appClassLoader; - } - - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - Class clazz = null; - - try { - clazz = mAppClassLoader.loadClass(name); - } catch (ClassNotFoundException e) { - // IGNORE. - } - if (clazz == null) { - clazz = super.loadClass(name, resolve); - } - - if (clazz == null) { - throw new ClassNotFoundException(); - } - - return clazz; - } -} diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java index d7802db0..968f73bb 100644 --- a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java @@ -1,10 +1,9 @@ package com.elderdrivers.riru.edxp.util; -import android.annotation.SuppressLint; -import android.os.Build; -import android.os.Process; import android.text.TextUtils; +import com.elderdrivers.riru.edxp.config.ConfigManager; + import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -12,12 +11,8 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE; - public class FileUtils { - public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; - /** * Delete a file or a directory and its children. * @@ -52,8 +47,9 @@ public class FileUtils { public static void writeLine(File file, String line) { try { + //noinspection ResultOfMethodCallIgnored file.createNewFile(); - } catch (IOException ex) { + } catch (IOException ignored) { } try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writer.write(line); @@ -75,11 +71,7 @@ public class FileUtils { return dataDir.substring(lastIndex + 1); } - // FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet. - @SuppressLint("SdCardPath") public static String getDataPathPrefix() { - int userId = Process.myUid() / PER_USER_RANGE; - String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/"; - return String.format(format, userId); + return ConfigManager.getDataPathPrefix(); } } diff --git a/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProxyClassLoader.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProxyClassLoader.java new file mode 100644 index 00000000..8b6ab186 --- /dev/null +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProxyClassLoader.java @@ -0,0 +1,30 @@ +package com.elderdrivers.riru.edxp.util; + +public class ProxyClassLoader extends ClassLoader { + + private final ClassLoader mClassLoader; + + public ProxyClassLoader(ClassLoader parentCL, ClassLoader appCL) { + super(parentCL); + mClassLoader = appCL; + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class clazz = null; + + try { + clazz = mClassLoader.loadClass(name); + } catch (ClassNotFoundException ignored) { + } + + if (clazz == null) { + clazz = super.loadClass(name, resolve); + if (clazz == null) { + throw new ClassNotFoundException(); + } + } + + return clazz; + } +} diff --git a/edxp-core/.gitignore b/edxp-core/.gitignore index 64538351..862c7cf2 100644 --- a/edxp-core/.gitignore +++ b/edxp-core/.gitignore @@ -4,7 +4,5 @@ /obj /release /template_override/module.prop -/template_override/riru_module.prop -/template_override/system /template_override/system_x86 *.iml \ No newline at end of file diff --git a/edxp-core/build.gradle b/edxp-core/build.gradle index e8bd8295..55cc6ce9 100644 --- a/edxp-core/build.gradle +++ b/edxp-core/build.gradle @@ -4,8 +4,8 @@ import org.gradle.internal.os.OperatingSystem apply plugin: 'com.android.library' // Values set here will be overriden by AppVeyor, feel free to modify during development. -def buildVersionName = 'v0.4.6.0_beta' -def buildVersionCode = 10000 +def buildVersionName = 'v0.4.6.3' +def buildVersionCode = 233 if (System.env.APPVEYOR_BUILD_VERSION != null) { buildVersionName = "v${System.getenv('appveyor_build_version')}" @@ -28,9 +28,9 @@ ext { yahfa_module_id = "riru_edxposed" sandhook_module_id = yahfa_module_id + "_sandhook" whale_module_id = yahfa_module_id + "_whale" - yahfa_authors = "solohsu, rk700 & MlgmXyysd" - sandhook_authors = "solohsu, ganyao114 & MlgmXyysd" - whale_authors = "solohsu, asLody & MlgmXyysd" + yahfa_authors = "solohsu, MlgmXyysd & rk700" + sandhook_authors = "solohsu, MlgmXyysd & ganyao114" + whale_authors = "solohsu, MlgmXyysd & asLody" riruModuleId = "edxp" zipPathMagiskRelease = "$buildDir/tmp/release/magisk" @@ -107,7 +107,7 @@ task copyDexmakerJar { } task cleanTemplate(type: Delete) { - delete file(templateSystemPath), file(templateSystemx86Path) + delete file(templateSystemx86Path) } afterEvaluate { @@ -148,11 +148,6 @@ afterEvaluate { versionCode: "$versionCode", authorList: "$authorList") filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf")) } - copy { - from "${templateRootPath}/module.prop" - into templateRootPath - rename "module.prop", "riru_module.prop" - } } def libPathRelease = "${buildDir}/intermediates/cmake/${variantLowered}/obj" doLast { @@ -160,19 +155,15 @@ afterEvaluate { from "${projectDir}/template_override" into zipPathMagiskRelease } - copy { - from "${projectDir}/template_override/common/util_functions.sh" - into "${zipPathMagiskRelease}/common" - filter { line -> line - .replaceAll('%VERSION%', "$version") - .replaceAll('%VERSION_CODE%', "$versionCode") - .replaceAll('%BACKEND%', "$backendCapped") } - filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf")) - } - copy { - from 'template_override/riru_module.prop' - into "$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}" - } +// copy { +// from "${projectDir}/template_override/util_functions.sh" +// into "${zipPathMagiskRelease}/" +// filter { line -> line +// .replaceAll('%VERSION%', "$version") +// .replaceAll('%VERSION_CODE%', "$versionCode") +// .replaceAll('%BACKEND%', "$backendCapped") } +// filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf")) +// } copy { from "$libPathRelease/armeabi-v7a" into "$zipPathMagiskRelease/system/lib" @@ -189,15 +180,12 @@ afterEvaluate { from "$libPathRelease/x86_64" into "$zipPathMagiskRelease/system_x86/lib64" } - - file("$zipPathMagiskRelease/riru_module.prop").delete() - file("$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}/riru_module.prop").renameTo("$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}/module.prop") } } def zipTask = task("zip${backendCapped}${variantCapped}", type: Zip) { dependsOn prepareMagiskFilesTask - archiveName "magisk-${module_name}-${backend}-${project.version}-${variantLowered}.zip" + archiveName "${module_name}-${backend}-${project.version}-${variantLowered}.zip" destinationDir file("$projectDir/release") from "$zipPathMagiskRelease" } @@ -206,7 +194,7 @@ afterEvaluate { dependsOn zipTask workingDir "${projectDir}/release" def commands = ["adb", "push", - "magisk-${module_name}-${backend}-${project.version}-${variantLowered}.zip", + "${module_name}-${backend}-${project.version}-${variantLowered}.zip", "/sdcard/"] if (is_windows) { commandLine 'cmd', '/c', commands.join(" ") diff --git a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c index fc49eed4..c9fda466 100644 --- a/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c +++ b/edxp-core/src/main/cpp/external/yahfa/src/HookMain.c @@ -20,6 +20,7 @@ static int OFFSET_access_flags_in_ArtMethod; static size_t ArtMethodSize; static int kAccNative = 0x0100; static int kAccCompileDontBother = 0x01000000; +static int kAccFastInterpreterToInterpreterInvoke = 0x40000000; static inline uint16_t read16(void *addr) { return *((uint16_t *) addr); @@ -29,8 +30,8 @@ static inline uint32_t read32(void *addr) { return *((uint32_t *) addr); } -static inline uint64_t read64(void *addr) { - return *((uint64_t *) addr); +static inline void write32(void *addr, uint32_t value) { + *((uint32_t *) addr) = value; } void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) { @@ -122,11 +123,7 @@ void setNonCompilable(void *method) { int access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod); LOGI("setNonCompilable: access flags is 0x%x", access_flags); access_flags |= kAccCompileDontBother; - memcpy( - (char *) method + OFFSET_access_flags_in_ArtMethod, - &access_flags, - 4 - ); + write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); } bool setNativeFlag(void *method, bool isNative) { @@ -135,15 +132,15 @@ bool setNativeFlag(void *method, bool isNative) { int old_access_flags = access_flags; if (isNative) { access_flags |= kAccNative; + if (SDKVersion >= ANDROID_Q) { + // On API 29 whether to use the fast path or not is cached in the ART method structure + access_flags &= ~kAccFastInterpreterToInterpreterInvoke; + } } else { access_flags &= ~kAccNative; } if (access_flags != old_access_flags) { - memcpy( - (char *) method + OFFSET_access_flags_in_ArtMethod, - &access_flags, - 4 - ); + write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags); return true; } return false; diff --git a/edxp-core/src/main/cpp/main/include/art/runtime/oat_file_manager.h b/edxp-core/src/main/cpp/main/include/art/runtime/oat_file_manager.h index 2f10b5b0..a9445ee5 100644 --- a/edxp-core/src/main/cpp/main/include/art/runtime/oat_file_manager.h +++ b/edxp-core/src/main/cpp/main/include/art/runtime/oat_file_manager.h @@ -17,7 +17,10 @@ namespace art { if (api_level == ANDROID_P) { HOOK_FUNC(SetOnlyUseSystemOatFiles, "_ZN3art14OatFileManager24SetOnlyUseSystemOatFilesEv"); - + } + if (api_level == ANDROID_Q) { + HOOK_FUNC(SetOnlyUseSystemOatFiles, + "_ZN3art14OatFileManager24SetOnlyUseSystemOatFilesEbb"); } }; diff --git a/edxp-core/src/main/cpp/main/include/config.h b/edxp-core/src/main/cpp/main/include/config.h index 4c53f3e9..1075f09a 100644 --- a/edxp-core/src/main/cpp/main/include/config.h +++ b/edxp-core/src/main/cpp/main/include/config.h @@ -29,6 +29,8 @@ namespace edxp { static constexpr auto kLibArtName = "libart.so"; static constexpr auto kLibFwkName = "libandroid_runtime.so"; + static constexpr auto kLibWhaleName = "libwhale.edxp.so"; + static constexpr auto kLibSandHookName = "libsandhook.edxp.so"; static const auto kLibBasePath = std::string(LP_SELECT("/system/lib/", "/system/lib64/")); static const auto kLibRuntimeBasePath = std::string( @@ -36,8 +38,9 @@ namespace edxp { static const auto kLibArtPath = (GetAndroidApiLevel() >= ANDROID_Q ? kLibRuntimeBasePath : kLibBasePath) + kLibArtName; - static const auto kLibWhalePath = kLibBasePath + "libwhale.edxp.so"; - static const auto kLibSandHookPath = kLibBasePath + "libsandhook.edxp.so"; + + static const auto kLibWhalePath = kLibBasePath + kLibWhaleName; + static const auto kLibSandHookPath = kLibBasePath + kLibSandHookName; static const auto kLibFwPath = kLibBasePath + "libandroidfw.so"; static const auto kLibDlPath = kLibBasePath + "libdl.so"; static const auto kLibFwkPath = kLibBasePath + kLibFwkName; diff --git a/edxp-core/src/main/cpp/main/src/config_manager.cpp b/edxp-core/src/main/cpp/main/src/config_manager.cpp index 1595955f..8e3cf37a 100644 --- a/edxp-core/src/main/cpp/main/src/config_manager.cpp +++ b/edxp-core/src/main/cpp/main/src/config_manager.cpp @@ -30,18 +30,12 @@ namespace edxp { LOGI("using installer %s", kPrimaryInstallerPkgName); return kPrimaryInstallerPkgName; } - data_test_path = data_path_prefix_ + kSecondaryInstallerPkgName; - if (access(data_test_path.c_str(), F_OK) == 0) { - LOGI("using installer %s", kSecondaryInstallerPkgName); - return kSecondaryInstallerPkgName; - } data_test_path = data_path_prefix_ + kLegacyInstallerPkgName; if (access(data_test_path.c_str(), F_OK) == 0) { LOGI("using installer %s", kLegacyInstallerPkgName); return kLegacyInstallerPkgName; } - LOGE("no supported installer app found, using primary as default %s", - kPrimaryInstallerPkgName); + LOGE("no supported installer app found, using default: %s", kPrimaryInstallerPkgName); return kPrimaryInstallerPkgName; } @@ -53,7 +47,7 @@ namespace edxp { while ((dent = readdir(dir)) != nullptr) { if (dent->d_type == DT_REG) { const char *fileName = dent->d_name; - LOGI("whitelist: %s", fileName); + LOGI(" whitelist: %s", fileName); white_list_default_.emplace_back(fileName); } } @@ -64,7 +58,7 @@ namespace edxp { while ((dent = readdir(dir)) != nullptr) { if (dent->d_type == DT_REG) { const char *fileName = dent->d_name; - LOGI("blacklist: %s", fileName); + LOGI(" blacklist: %s", fileName); black_list_default_.emplace_back(fileName); } } @@ -72,37 +66,62 @@ namespace edxp { } } - void ConfigManager::InitOnce() { - if (!initialized_) { - use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N; - data_path_prefix_ = use_prot_storage_ ? "/data/user_de/0/" : "/data/user/0/"; + void ConfigManager::UpdateConfigPath(const uid_t user) { + if (last_user_ != user) { + LOGI("updating config data paths from %u to %u...", last_user_, user); + last_user_ = user; + } - installer_pkg_name_ = RetrieveInstallerPkgName(); - base_config_path_ = GetConfigPath(""); - blacklist_path_ = GetConfigPath("blacklist/"); - whitelist_path_ = GetConfigPath("whitelist/"); - use_whitelist_path_ = GetConfigPath("usewhitelist"); + const char *format = use_prot_storage_ ? "/data/user_de/%u/" : "/data/user/%u/"; + char buff[PATH_MAX]; + snprintf(buff, sizeof(buff), format, last_user_); + data_path_prefix_ = buff; - dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0; - black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0; - deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0; - resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0; + installer_pkg_name_ = RetrieveInstallerPkgName(); + base_config_path_ = GetConfigPath(""); + blacklist_path_ = GetConfigPath("blacklist/"); + whitelist_path_ = GetConfigPath("whitelist/"); + use_whitelist_path_ = GetConfigPath("usewhitelist"); - // use_white_list snapshot - use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0; - LOGI("black/white list mode: %s, using whitelist: %s", - BoolToString(black_white_list_enabled_), BoolToString(use_white_list_snapshot_)); - LOGI("dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_)); - LOGI("resources hook: %s", BoolToString(resources_hook_enabled_)); - LOGI("deopt boot image: %s", BoolToString(deopt_boot_image_enabled_)); - if (black_white_list_enabled_) { - SnapshotBlackWhiteList(); - } - initialized_ = true; + dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0; + black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0; + deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0; + resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0; + no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0; + hidden_api_bypass_enabled_ = access(GetConfigPath("disable_hidden_api_bypass").c_str(), F_OK) != 0; + + // use_white_list snapshot + use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0; + LOGI("data path prefix: %s", data_path_prefix_.c_str()); + LOGI(" application list mode: %s", BoolToString(black_white_list_enabled_)); + LOGI(" using whitelist: %s", BoolToString(use_white_list_snapshot_)); + LOGI(" dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_)); + LOGI(" resources hook: %s", BoolToString(resources_hook_enabled_)); + LOGI(" deopt boot image: %s", BoolToString(deopt_boot_image_enabled_)); + LOGI(" no module log: %s", BoolToString(no_module_log_enabled_)); + LOGI(" hidden api bypass: %s", BoolToString(hidden_api_bypass_enabled_)); + if (black_white_list_enabled_) { + SnapshotBlackWhiteList(); } } - bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) const { + bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) { + // zygote always starts with `uid == 0` and then fork into different user. + // so we have to check if we are the correct user or not. + uid_t user = 0; + char package_name[PATH_MAX]; + if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%u/%s", &user, package_name) != 2) { + if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) { + package_name[0] = '\0'; + LOGE("can't parse %s", app_data_dir.c_str()); + return false; // default to no hooking for safety + } + } + + if (last_user_ != user) { + UpdateConfigPath(user); + } + if (!black_white_list_enabled_) { return true; } @@ -115,17 +134,7 @@ namespace edxp { app_data_dir.c_str()); use_white_list = use_white_list_snapshot_; } - int user = 0; - char package_name[PATH_MAX]; - if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%d/%s", &user, package_name) != 2) { - if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) { - package_name[0] = '\0'; - LOGE("can't parse %s", app_data_dir.c_str()); - return !use_white_list; - } - } if (strcmp(package_name, kPrimaryInstallerPkgName) == 0 - || strcmp(package_name, kSecondaryInstallerPkgName) == 0 || strcmp(package_name, kLegacyInstallerPkgName) == 0) { // always hook installer apps return true; @@ -164,6 +173,10 @@ namespace edxp { return dynamic_modules_enabled_; } + ALWAYS_INLINE bool ConfigManager::IsNoModuleLogEnabled() const { + return no_module_log_enabled_; + } + ALWAYS_INLINE bool ConfigManager::IsResourcesHookEnabled() const { return resources_hook_enabled_; } @@ -172,20 +185,38 @@ namespace edxp { return deopt_boot_image_enabled_; } - ALWAYS_INLINE std::string ConfigManager::GetInstallerPkgName() const { + ALWAYS_INLINE bool ConfigManager::IsHiddenAPIBypassEnabled() const { + return hidden_api_bypass_enabled_; + } + + ALWAYS_INLINE std::string ConfigManager::GetInstallerPackageName() const { return installer_pkg_name_; } + ALWAYS_INLINE std::string ConfigManager::GetXposedPropPath() const { + return kXposedPropPath; + } + + ALWAYS_INLINE std::string ConfigManager::GetLibSandHookName() const { + return kLibSandHookName; + } + + ALWAYS_INLINE std::string ConfigManager::GetLibWhaleName() const { + return kLibWhaleName; + } + + ALWAYS_INLINE std::string ConfigManager::GetDataPathPrefix() const { + return data_path_prefix_; + } + ALWAYS_INLINE std::string ConfigManager::GetConfigPath(const std::string &suffix) const { return data_path_prefix_ + installer_pkg_name_ + "/conf/" + suffix; }; ConfigManager::ConfigManager() { - InitOnce(); - } - - ConfigManager::~ConfigManager() { - initialized_ = false; + use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N; + last_user_ = 0; + UpdateConfigPath(last_user_); } } \ No newline at end of file diff --git a/edxp-core/src/main/cpp/main/src/config_manager.h b/edxp-core/src/main/cpp/main/src/config_manager.h index fb97f63a..f1b9faf1 100644 --- a/edxp-core/src/main/cpp/main/src/config_manager.h +++ b/edxp-core/src/main/cpp/main/src/config_manager.h @@ -8,9 +8,9 @@ namespace edxp { - static constexpr const char *kPrimaryInstallerPkgName = "com.solohsu.android.edxp.manager"; - static constexpr const char *kSecondaryInstallerPkgName = "org.meowcat.edxposed.manager"; + static constexpr const char *kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager"; static constexpr const char *kLegacyInstallerPkgName = "de.robv.android.xposed.installer"; + static constexpr auto kXposedPropPath = "/system/framework/edconfig.jar"; class ConfigManager { public: @@ -30,13 +30,28 @@ namespace edxp { bool IsDeoptBootImageEnabled() const; - std::string GetInstallerPkgName() const; + bool IsNoModuleLogEnabled() const; - bool IsAppNeedHook(const std::string &app_data_dir) const; + bool IsHiddenAPIBypassEnabled() const; + std::string GetInstallerPackageName() const; + + std::string GetXposedPropPath() const; + + std::string GetLibSandHookName() const; + + std::string GetLibWhaleName() const; + + std::string GetDataPathPrefix() const; + + std::string GetConfigPath(const std::string &suffix) const; + + bool IsAppNeedHook(const std::string &app_data_dir); + + bool hidden_api_bypass_enabled_ = false; private: inline static ConfigManager *instance_; - bool initialized_ = false; + uid_t last_user_ = false; bool use_prot_storage_ = true; std::string data_path_prefix_; std::string installer_pkg_name_; @@ -47,6 +62,7 @@ namespace edxp { bool black_white_list_enabled_ = false; bool dynamic_modules_enabled_ = false; bool deopt_boot_image_enabled_ = false; + bool no_module_log_enabled_ = false; bool resources_hook_enabled_ = true; // snapshot at boot bool use_white_list_snapshot_ = false; @@ -55,17 +71,12 @@ namespace edxp { ConfigManager(); - ~ConfigManager(); - - void InitOnce(); + void UpdateConfigPath(const uid_t user); void SnapshotBlackWhiteList(); std::string RetrieveInstallerPkgName() const; - - std::string GetConfigPath(const std::string &suffix) const; }; - } // namespace edxp diff --git a/edxp-core/src/main/cpp/main/src/jni/edxp_config_manager.cpp b/edxp-core/src/main/cpp/main/src/jni/edxp_config_manager.cpp index f62dfbd7..21983d4c 100644 --- a/edxp-core/src/main/cpp/main/src/jni/edxp_config_manager.cpp +++ b/edxp-core/src/main/cpp/main/src/jni/edxp_config_manager.cpp @@ -22,8 +22,36 @@ namespace edxp { return (jboolean) ConfigManager::GetInstance()->IsDeoptBootImageEnabled(); } + static jboolean ConfigManager_isNoModuleLogEnabled(JNI_START) { + return (jboolean) ConfigManager::GetInstance()->IsNoModuleLogEnabled(); + } + static jstring ConfigManager_getInstallerPackageName(JNI_START) { - return env->NewStringUTF(ConfigManager::GetInstance()->GetInstallerPkgName().c_str()); + return env->NewStringUTF(ConfigManager::GetInstance()->GetInstallerPackageName().c_str()); + } + + static jstring ConfigManager_getXposedPropPath(JNI_START) { + return env->NewStringUTF(ConfigManager::GetInstance()->GetXposedPropPath().c_str()); + } + + static jstring ConfigManager_getLibWhaleName(JNI_START) { + return env->NewStringUTF(ConfigManager::GetInstance()->GetLibWhaleName().c_str()); + } + + static jstring ConfigManager_getLibSandHookName(JNI_START) { + return env->NewStringUTF(ConfigManager::GetInstance()->GetLibSandHookName().c_str()); + } + + static jstring ConfigManager_getDataPathPrefix(JNI_START) { + return env->NewStringUTF(ConfigManager::GetInstance()->GetDataPathPrefix().c_str()); + } + + static jstring ConfigManager_getInstallerConfigPath(JNI_START, jstring jSuffix) { + const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE); + auto result = ConfigManager::GetInstance()->GetConfigPath(suffix); + env->ReleaseStringUTFChars(jSuffix, suffix); + return env->NewStringUTF(result.c_str()); + } static jboolean ConfigManager_isAppNeedHook(JNI_START, jstring appDataDir) { @@ -38,7 +66,13 @@ namespace edxp { NATIVE_METHOD(ConfigManager, isDynamicModulesEnabled, "()Z"), NATIVE_METHOD(ConfigManager, isResourcesHookEnabled, "()Z"), NATIVE_METHOD(ConfigManager, isDeoptBootImageEnabled, "()Z"), + NATIVE_METHOD(ConfigManager, isNoModuleLogEnabled, "()Z"), NATIVE_METHOD(ConfigManager, getInstallerPackageName, "()Ljava/lang/String;"), + NATIVE_METHOD(ConfigManager, getXposedPropPath, "()Ljava/lang/String;"), + NATIVE_METHOD(ConfigManager, getLibSandHookName, "()Ljava/lang/String;"), + NATIVE_METHOD(ConfigManager, getLibWhaleName, "()Ljava/lang/String;"), + NATIVE_METHOD(ConfigManager, getDataPathPrefix, "()Ljava/lang/String;"), + NATIVE_METHOD(ConfigManager, getInstallerConfigPath, "(Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(ConfigManager, isAppNeedHook, "(Ljava/lang/String;)Z"), }; diff --git a/edxp-core/src/main/cpp/main/src/native_hook.cpp b/edxp-core/src/main/cpp/main/src/native_hook.cpp index fe3ea4c7..4e42a99a 100644 --- a/edxp-core/src/main/cpp/main/src/native_hook.cpp +++ b/edxp-core/src/main/cpp/main/src/native_hook.cpp @@ -66,7 +66,7 @@ namespace edxp { } hook_func = reinterpret_cast(hook_func_symbol); - if (api_level >= ANDROID_P) { + if (api_level > ANDROID_P) { ScopedDlHandle dl_handle(kLibDlPath.c_str()); void *handle = dl_handle.Get(); HOOK_FUNC(mydlopen, "__loader_dlopen"); @@ -83,7 +83,9 @@ namespace edxp { if (art_hooks_installed) { return; } - art::hidden_api::DisableHiddenApi(art_handle, hook_func); + if (ConfigManager::GetInstance() -> IsHiddenAPIBypassEnabled()) { + art::hidden_api::DisableHiddenApi(art_handle, hook_func); + } art::Runtime::Setup(art_handle, hook_func); art::gc::Heap::Setup(art_handle, hook_func); art::ClassLinker::Setup(art_handle, hook_func); diff --git a/edxp-core/template_override/EdXposed.apk b/edxp-core/template_override/EdXposed.apk new file mode 100644 index 00000000..fbe85329 Binary files /dev/null and b/edxp-core/template_override/EdXposed.apk differ diff --git a/edxp-core/template_override/META-INF/com/google/android/update-binary b/edxp-core/template_override/META-INF/com/google/android/update-binary index 923d0bd5..29240cda 100644 --- a/edxp-core/template_override/META-INF/com/google/android/update-binary +++ b/edxp-core/template_override/META-INF/com/google/android/update-binary @@ -1,12 +1,15 @@ #!/sbin/sh -TMPDIR=/dev/tmp -MOUNTPATH=/dev/magisk_img +################# +# Initialization +################# -# Default permissions umask 022 -# Initial cleanup +# Global vars +TMPDIR=/dev/tmp +PERSISTDIR=/sbin/.magisk/mirror/persist + rm -rf $TMPDIR 2>/dev/null mkdir -p $TMPDIR @@ -14,20 +17,33 @@ mkdir -p $TMPDIR ui_print() { echo "$1"; } require_new_magisk() { - ui_print "***********************************" - ui_print " Please install the latest Magisk! " - ui_print "***********************************" + ui_print "*******************************" + ui_print " Please install Magisk v19.0+! " + ui_print "*******************************" exit 1 } -imageless_magisk() { - [ $MAGISK_VER_CODE -gt 18100 ] +is_legacy_script() { + unzip -l "$ZIPFILE" install.sh | grep -q install.sh return $? } -########################################################################################## +print_modname() { + local len + len=`echo -n $MODNAME | wc -c` + len=$((len + 2)) + local pounds=`printf "%${len}s" | tr ' ' '*'` + ui_print "$pounds" + ui_print " $MODNAME " + ui_print "$pounds" + ui_print "*******************" + ui_print " Powered by Magisk " + ui_print "*******************" +} + +############## # Environment -########################################################################################## +############## OUTFD=$2 ZIPFILE=$3 @@ -35,12 +51,9 @@ ZIPFILE=$3 mount /data 2>/dev/null # Load utility functions -if [ -f /data/adb/magisk/util_functions.sh ]; then - . /data/adb/magisk/util_functions.sh - NVBASE=/data/adb -else - require_new_magisk -fi +[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk +. /data/adb/magisk/util_functions.sh +[ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk # Preperation for flashable zips setup_flashable @@ -54,98 +67,107 @@ api_level_arch_detect # Setup busybox and binaries $BOOTMODE && boot_actions || recovery_actions -########################################################################################## +############## # Preparation -########################################################################################## +############## -# Extract common files -unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 - -[ ! -f $TMPDIR/install.sh ] && abort "! Unable to extract zip file!" -# Load install script -. $TMPDIR/install.sh - -if imageless_magisk; then - $BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules - MODULEROOT=$NVBASE/$MODDIRNAME -else - $BOOTMODE && IMGNAME=magisk_merge.img || IMGNAME=magisk.img - IMG=$NVBASE/$IMGNAME - request_zip_size_check "$ZIPFILE" - mount_magisk_img - MODULEROOT=$MOUNTPATH -fi +# Extract prop file +unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2 +[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!" +$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules +MODULEROOT=$NVBASE/$MODDIRNAME MODID=`grep_prop id $TMPDIR/module.prop` MODPATH=$MODULEROOT/$MODID - -print_modname - -ui_print "******************************" -ui_print "Powered by Magisk (@topjohnwu)" -ui_print "******************************" - -########################################################################################## -# Install -########################################################################################## +MODNAME=`grep_prop name $TMPDIR/module.prop` # Create mod paths rm -rf $MODPATH 2>/dev/null mkdir -p $MODPATH -on_install +########## +# Install +########## -# Remove placeholder -rm -f $MODPATH/system/placeholder 2>/dev/null +if is_legacy_script; then + unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2 -# Custom uninstaller -[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh + # Load install script + . $TMPDIR/install.sh -# Auto Mount -if imageless_magisk; then + # Callbacks + print_modname + on_install + + # Custom uninstaller + [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh + + # Skip mount $SKIPMOUNT && touch $MODPATH/skip_mount + + # prop file + $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop + + # Module info + cp -af $TMPDIR/module.prop $MODPATH/module.prop + + # post-fs-data scripts + $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh + + # service scripts + $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh + + ui_print "- Setting permissions" + set_permissions else - $SKIPMOUNT || touch $MODPATH/auto_mount -fi + print_modname -# prop files -$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop + unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2 -# Module info -cp -af $TMPDIR/module.prop $MODPATH/module.prop -if $BOOTMODE; then - # Update info for Magisk Manager - if imageless_magisk; then - mktouch $NVBASE/modules/$MODID/update - cp -af $TMPDIR/module.prop $NVBASE/modules/$MODID/module.prop - else - mktouch /sbin/.magisk/img/$MODID/update - cp -af $TMPDIR/module.prop /sbin/.magisk/img/$MODID/module.prop + if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then + ui_print "- Extracting module files" + unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2 + + # Default permissions + set_perm_recursive $MODPATH 0 0 0755 0644 fi + + # Load customization script + [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh fi -# post-fs-data mode scripts -$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh - -# service mode scripts -$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh - # Handle replace folders for TARGET in $REPLACE; do + ui_print "- Replace target: $TARGET" mktouch $MODPATH$TARGET/.replace done -ui_print "- Setting permissions" -set_permissions +if $BOOTMODE; then + # Update info for Magisk Manager + mktouch $NVBASE/modules/$MODID/update + cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop +fi -########################################################################################## +# Copy over custom sepolicy rules +if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then + ui_print "- Installing custom sepolicy patch" + PERSISTMOD=$PERSISTDIR/magisk/$MODID + mkdir -p $PERSISTMOD + cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule +fi + +# Remove stuffs that don't belong to modules +rm -rf \ +$MODPATH/system/placeholder $MODPATH/customize.sh \ +$MODPATH/README.md $MODPATH/.git* 2>/dev/null + +############## # Finalizing -########################################################################################## +############## cd / -imageless_magisk || unmount_magisk_img $BOOTMODE || recovery_cleanup -rm -rf $TMPDIR $MOUNTPATH +rm -rf $TMPDIR ui_print "- Done" -exit 0 \ No newline at end of file +exit 0 diff --git a/edxp-core/template_override/README.md b/edxp-core/template_override/README.md new file mode 100644 index 00000000..5949a9e2 --- /dev/null +++ b/edxp-core/template_override/README.md @@ -0,0 +1,47 @@ +# EdXposed Framework + +[简体中文](https://github.com/ElderDrivers/EdXposed/wiki/%E7%AE%80%E4%BB%8B) + +## Introduction + +A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework, supports Android 8.0 ~ **10**. + +> Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo. As all changes are done in the memory, you just need to deactivate the module and reboot to get your original system back. There are many other advantages, but here is just one more: Multiple modules can do changes to the same part of the system or app. With modified APKs, you to decide for one. No way to combine them, unless the author builds multiple APKs with different combinations. + +What are the differences between EdXposed Framework and Xposed Framework? + +1. EdXposed fully supports Android Pie and Q (even R) +2. EdXposed have App List mode. Only the apps you want to apply Xposed modules are hooked. Other apps in system run in a completely clean environment +3. EdXposed doesn't need to reboot system to active most modules +4. EdXposed is hard to detect. EdXposed use Riru to inject, doesn't modify the libart and app_process + +## How to use ? + +To put it simply, just follow these steps: + +1. Install Magisk +2. Flash the Riru - Core Magisk module. You can find it in [Riru release page](https://github.com/RikkaApps/Riru/releases). +3. Flash the Riru - EdXposed Magisk module. You can find it in [EdXposed release page](https://github.com/ElderDrivers/EdXposed/releases). +4. Install EdXposed Manager. You can find it in [EdXposed Manager release page](https://github.com/ElderDrivers/EdXposedManager/releases). +5. Reboot :) + +More informations in detail: + +[**Official Website**](http://edxp.meowcat.org/) + +[**Wiki**](https://github.com/ElderDrivers/EdXposed/wiki) + +[**Telegram Channel**](https://t.me/EdXposed/) + +## Community Discussion + +- QQ Group: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f) +- Telegram: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat) + +Notice: These community group don't accept any bug report, please use [Get help](#get-help) to report. + +## Get Help + +- GitHub Issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/) + +- Notice(for Chinese): In view of the low quality of issues submitted, please read the Chinese user report first[EdXposedIssuesReport_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(If you don't read the instructions, the submitted issue is likely to be closed) diff --git a/edxp-core/template_override/common/post-fs-data.sh b/edxp-core/template_override/common/post-fs-data.sh deleted file mode 100644 index ba9a0020..00000000 --- a/edxp-core/template_override/common/post-fs-data.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/system/bin/sh -# Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... -# This will make your scripts compatible even if Magisk change its mount point in the future -MODDIR=${0%/*} - -# This script will be executed in post-fs-data mode -# More info in the main Magisk thread - -# necessary for using mmap in system_server process -#supolicy --live "allow system_server system_server process {execmem}" -# supolicy --live "allow system_server system_server memprotect {mmap_zero}" - -# for built-in apps // TODO maybe narrow down the target classes -#supolicy --live "allow coredomain coredomain process {execmem}" - -# read configs set in our app -#supolicy --live "allow coredomain app_data_file * *" -#supolicy --live "attradd {system_app platform_app} mlstrustedsubject" - -# read module apk file in zygote -#supolicy --live "allow zygote apk_data_file * *" - -. ${MODDIR}/util_functions.sh - -start_log_catchers diff --git a/edxp-core/template_override/common/service.sh b/edxp-core/template_override/common/service.sh deleted file mode 100644 index 45124171..00000000 --- a/edxp-core/template_override/common/service.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/system/bin/sh -# Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/... -# This will make your scripts compatible even if Magisk change its mount point in the future -MODDIR=${0%/*} - -# This script will be executed in late_start service mode -# More info in the main Magisk thread diff --git a/edxp-core/template_override/common/util_functions.sh b/edxp-core/template_override/common/util_functions.sh deleted file mode 100644 index e4e83b44..00000000 --- a/edxp-core/template_override/common/util_functions.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/system/bin/sh - -EDXP_VERSION="%VERSION% (%BACKEND%)" -ANDROID_SDK=`getprop ro.build.version.sdk` -BUILD_DESC=`getprop ro.build.description` -PRODUCT=`getprop ro.build.product` -MANUFACTURE=`getprop ro.product.manufacturer` -BRAND=`getprop ro.product.brand` -FINGERPRINT=`getprop ro.build.fingerprint` -ARCH=`getprop ro.product.cpu.abi` -DEVICE=`getprop ro.product.device` -ANDROID=`getprop ro.build.version.release` -BUILD=`getprop ro.build.id` -MAGISKV=`su -v` -MAGISKC=`su -V` - -setup_log_path () { - EDXP_INSTALLER=com.solohsu.android.edxp.manager - EDXP_MANAGER=org.meowcat.edxposed.manager - XP_INSTALLER=de.robv.android.xposed.installer - PATH_PREFIX_PROT=/data/user_de/0/ - PATH_PREFIX_LEGACY=/data/user/0/ - if [[ ${ANDROID_SDK} -ge 24 ]]; then - PATH_PREFIX=${PATH_PREFIX_PROT} - else - PATH_PREFIX=${PATH_PREFIX_LEGACY} - fi - DEFAULT_BASE_PATH=${PATH_PREFIX}${EDXP_INSTALLER} - BASE_PATH=${DEFAULT_BASE_PATH} - if [[ ! -d ${BASE_PATH} ]] - then - BASE_PATH=${PATH_PREFIX}${EDXP_MANAGER} - if [[ ! -d ${BASE_PATH} ]] - then - BASE_PATH=${PATH_PREFIX}${XP_INSTALLER} - if [[ ! -d ${BASE_PATH} ]] - then - BASE_PATH=${DEFAULT_BASE_PATH} - fi - fi - fi - LOG_PATH=${BASE_PATH}/log - CONF_PATH=${BASE_PATH}/conf - DISABLE_VERBOSE_LOG_FILE=${CONF_PATH}/disable_verbose_log - LOG_VERBOSE=true - if [[ -f ${DISABLE_VERBOSE_LOG_FILE} ]]; then LOG_VERBOSE=false; fi -} - -start_log_cather () { - LOG_FILE_NAME=$1 - LOG_TAG_FILTERS=$2 - CLEAN_OLD=$3 - START_NEW=$4 - LOG_FILE=${LOG_PATH}/${LOG_FILE_NAME} - mkdir -p ${LOG_PATH} - if [[ ${CLEAN_OLD} = true ]]; then - rm -rf ${LOG_FILE} - fi - if [[ ${START_NEW} = false ]]; then - return - fi - touch ${LOG_FILE} - chmod 777 ${LOG_FILE} - echo "--------- beginning of head">>${LOG_FILE} - echo "EdXposed Log">>${LOG_FILE} - echo "Powered by Log Catcher">>${LOG_FILE} - echo "QQ chat group 855219808">>${LOG_FILE} - echo "--------- beginning of system info">>${LOG_FILE} - echo "Android version: ${ANDROID}">>${LOG_FILE} - echo "Android sdk: ${ANDROID_SDK}">>${LOG_FILE} - echo "Android build: ${BUILD}">>${LOG_FILE} - echo "Fingerprint: ${FINGERPRINT}">>${LOG_FILE} - echo "ROM build description: ${BUILD_DESC}">>${LOG_FILE} - echo "EdXposed Version: ${EDXP_VERSION}">>${LOG_FILE} - echo "Architecture: ${ARCH}">>${LOG_FILE} - echo "Device: ${DEVICE}">>${LOG_FILE} - echo "Manufacture: ${MANUFACTURE}">>${LOG_FILE} - echo "Brand: ${BRAND}">>${LOG_FILE} - echo "Product: ${PRODUCT}">>${LOG_FILE} - echo "Magisk: ${MAGISKV}(${MAGISKC})">>${LOG_FILE} - logcat -f ${LOG_FILE} *:S ${LOG_TAG_FILTERS} & -} - -start_verbose_log_catcher () { - start_log_cather all.log "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE} -} - -start_bridge_log_catcher () { - start_log_cather error.log "XSharedPreferences:V EdXposed-Bridge:V" true true -} - -start_log_catchers () { - start_bridge_log_catcher - start_verbose_log_catcher -} - -setup_log_path diff --git a/edxp-core/template_override/customize.sh b/edxp-core/template_override/customize.sh new file mode 100644 index 00000000..2c34d089 --- /dev/null +++ b/edxp-core/template_override/customize.sh @@ -0,0 +1,350 @@ +SKIPUNZIP=1 + +getRandomNameExist() { + RAND_PATH=$4 + RAND_SUFFIX=$3 + RAND_PREFIX=$2 + RAND_DIGIT=$1 + RAND_RAND="$(cat /proc/sys/kernel/random/uuid|md5sum|cut -c 1-"${RAND_DIGIT}")" + RAND_PATH_EXIST=false + for TARGET in ${RAND_PATH}; do + if [[ -e "${TARGET}/${RAND_PREFIX}${RAND_RAND}${RAND_SUFFIX}" ]]; then + RAND_PATH_EXIST=true + fi + done + if [[ "${RAND_PATH_EXIST}" == true ]]; then + getRandomNameExist "${RAND_DIGIT}" "${RAND_PREFIX}" "${RAND_SUFFIX}" "${RAND_PATH}" + else + echo "${RAND_RAND}" + fi +} + +RIRU_PATH="/data/misc/riru" +RIRU_EDXP="$(getRandomNameExist 4 "libriru_" ".so" " +/system/lib +/system/lib64 +")" +RIRU_MODULES="${RIRU_PATH}/modules" +RIRU_TARGET="${RIRU_MODULES}/${RIRU_EDXP}" + +VERSION=$(grep_prop version "${TMPDIR}/module.prop") +RIRU_MIN_API_VERSION=$(grep_prop api "${TMPDIR}/module.prop") + +PROP_MODEL=$(getprop ro.product.model) +PROP_DEVICE=$(getprop ro.product.device) +PROP_PRODUCT=$(getprop ro.build.product) +PROP_BRAND=$(getprop ro.product.brand) +PROP_MANUFACTURER=$(getprop ro.product.manufacturer) + +JAR_EDXP="$(getRandomNameExist 8 "" ".jar" " +/system/framework +").jar" +JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".jar" " +/system/framework +").jar" +JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".jar" " +/system/framework +").jar" +JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" " +/system/framework +").jar" +LIB_RIRU_EDXP="libriru_${RIRU_EDXP}.so" +LIB_WHALE_EDXP="lib$(getRandomNameExist 10 "lib" ".so" " +/system/lib +/system/lib64 +").so" +LIB_SANDHOOK_EDXP="lib$(getRandomNameExist 13 "lib" ".so" " +/system/lib +/system/lib64 +").so" + +MODEL=" +HD1900 +HD1910 +" +DEVICE=" +OnePlus7T +OnePlus7TPro +" +PRODUCT=" +OnePlus7T +OnePlus7TPro +" +BRAND=" +HUAWEI +HONOR +" +MANUFACTURER=" +HUAWEI +" + +OLD_MAGISK=false +DETECTED_DEVICE=false +#NO_PERSIST=false +[[ "$(getenforce)" == "Enforcing" ]] && ENFORCE=true || ENFORCE=false + +abortC() { + rm -rf "${MODPATH}" + abort "$1" +} + +require_new_magisk() { +# if [[ "${NO_PERSIST}" == true ]]; then +# ui_print "******************************" +# ui_print "! Special device detected" +# ui_print "! But persist is not found in your device, SEPolicy rules will not take effect correctly" +# ui_print "! Deprecated custom Magisk v20.1 is required" +# ui_print "! Change Magisk update channel to http://edxp.meowcat.org/repo/version.json" +# ui_print "! And re-install Magisk" +# abortC "******************************" +# else + ui_print "******************************" + ui_print "! Special device detected" + ui_print "! Magisk v20.2+ or custom Magisk v20.1(Deprecated) is required" + ui_print "! You can update from 'Magisk Manager' or https://github.com/topjohnwu/Magisk/releases" + abortC "******************************" +# fi +} + +update_new_magisk() { + ui_print "******************************" + ui_print "- Deprecated custom Magisk v20.1 detected" + ui_print "- We will still keep the rule file for you" + ui_print "- You can update to the latest Magisk directly from official update channel" + ui_print "******************************" +} + +require_riru() { + ui_print "******************************" + ui_print "! Requirement module 'Riru - Core' is not installed" + ui_print "! You can download from 'Magisk Manager' or https://github.com/RikkaApps/Riru/releases" + abortC "******************************" +} + +require_new_riru() { + ui_print "******************************" + ui_print "! Old Riru ${1} (below v19) detected" + ui_print "! The latest version of 'Riru - Core' is required" + ui_print "! You can download from 'Magisk Manager' or https://github.com/RikkaApps/Riru/releases" + abortC "******************************" +} + +require_yahfa() { + ui_print "******************************" + ui_print "! Architecture x86 or x86_64 detected" + ui_print "! Only YAHFA variant supports x86 or x86_64 architecture devices" + ui_print "! You can download from 'Magisk Manager' or 'EdXposed Manager'" + abortC "******************************" +} + +require_new_android() { + ui_print "******************************" + ui_print "! Old Android ${1} (below Oreo) detected" + ui_print "! Only the original Xposed Framework can be used under Android 8.0" + ui_print "! You can download from 'Xposed Installer' or 'Magisk Manager(Systemless-ly)'" + ui_print "! Learn more: https://github.com/ElderDrivers/EdXposed/wiki/Available-Android-versions" + abortC "******************************" +} + +check_old_magisk_device() { + OLD_MAGISK=true + ui_print "******************************" + ui_print "- Old Magisk ${1} (below v20.2) detected" + ui_print "- The old Magisk may cause some problems (it may be fixed in new version)" + ui_print "- And support may be cancelled in subsequent versions" + ui_print "- In any case, you should update to the latest version in time" + ui_print "******************************" + if [[ "${DETECTED_DEVICE}" == true ]]; then + require_new_magisk + fi +} + +check_magisk_version() { + for TARGET in ${MODEL}; do + if [[ "${PROP_MODEL}" == "${TARGET}" ]]; then + DETECTED_DEVICE=true + fi + done + for TARGET in ${DEVICE}; do + if [[ "${PROP_DEVICE}" == "${TARGET}" ]]; then + DETECTED_DEVICE=true + fi + done + for TARGET in ${PRODUCT}; do + if [[ "${PROP_PRODUCT}" == "${TARGET}" ]]; then + DETECTED_DEVICE=true + fi + done + for TARGET in ${BRAND}; do + if [[ "${PROP_BRAND}" == "${TARGET}" ]]; then + DETECTED_DEVICE=true + fi + done + for TARGET in ${MANUFACTURER}; do + if [[ "${PROP_MANUFACTURER}" == "${TARGET}" ]]; then + DETECTED_DEVICE=true + fi + done + if [[ "${DETECTED_DEVICE}" == true ]]; then + ui_print "- Special device detected" + fi + ui_print "- Magisk version: ${MAGISK_VER_CODE}" + [[ ${MAGISK_VER_CODE} -ge 20101 ]] || check_old_magisk_device "${MAGISK_VER_CODE}" + [[ ${MAGISK_VER_CODE} -eq 20101 ]] && update_new_magisk +} + +check_riru_version() { + if [[ ! -f "${RIRU_PATH}/api_version" ]] && [[ ! -f "${RIRU_PATH}/api_version.new" ]]; then + require_riru + fi + RIRU_API_VERSION=$(cat "${RIRU_PATH}/api_version.new") || RIRU_API_VERSION=$(cat "${RIRU_PATH}/api_version") || RIRU_API_VERSION=0 + [[ "${RIRU_API_VERSION}" -eq "${RIRU_API_VERSION}" ]] || RIRU_API_VERSION=0 + ui_print "- Riru API version: ${RIRU_API_VERSION}" + if [[ "${RIRU_API_VERSION}" -lt ${RIRU_MIN_API_VERSION} ]]; then + require_new_riru ${RIRU_API_VERSION} + fi +} + +check_architecture() { + if [[ "${MODID}" == "riru_edxposed_sandhook" ]]; then + VARIANTS="SandHook" + else + VARIANTS="YAHFA" + fi + ui_print "- EdXposed Variant: ${VARIANTS}" + if [[ "${ARCH}" != "arm" && "${ARCH}" != "arm64" && "${ARCH}" != "x86" && "${ARCH}" != "x64" ]]; then + abortC "! Unsupported platform: ${ARCH}" + else + ui_print "- Device platform: ${ARCH}" + if [[ "${ARCH}" == "x86" || "${ARCH}" == "x64" ]]; then + if [[ "${VARIANTS}" == "SandHook" ]]; then + require_yahfa + fi + fi + fi +} + +check_android_version() { + if [[ ${API} -ge 26 ]]; then + ui_print "- Android sdk: ${API}" + else + require_new_android "${API}" + fi +} + +#check_persist() { +# if [[ "$(cat /proc/mounts | grep /sbin/.magisk/mirror/persist)" == "" ]]; then +# NO_PERSIST=true +# fi +#} + +ui_print "- EdXposed Version ${VERSION}" + +#check_persist +check_magisk_version +check_riru_version +check_architecture + +ui_print "- Extracting module files" +unzip -o "${ZIPFILE}" EdXposed.apk module.prop post-fs-data.sh sepolicy.rule system.prop uninstall.sh 'system/*' -d "${MODPATH}" >&2 + +if [[ "${ARCH}" == "x86" || "${ARCH}" == "x64" ]]; then + ui_print "- Replacing x86 and x86_64 libraries" + unzip -o "${ZIPFILE}" 'system_x86/*' -d "${MODPATH}" >&2 + rm -rf "${MODPATH}/system/lib" + rm -rf "${MODPATH}/system/lib64" + mv "${MODPATH}/system_x86/lib" "${MODPATH}/system/lib" + mv "${MODPATH}/system_x86/lib64" "${MODPATH}/system/lib64" + rm -rf "${MODPATH}/system_x86" +fi + +if [[ "${IS64BIT}" == false ]]; then + ui_print "- Removing 64-bit libraries" + rm -rf "${MODPATH}/system/lib64" +fi + +if [[ "$(pm path org.meowcat.edxposed.manager)" == "" && "$(pm path de.robv.android.xposed.installer)" == "" ]]; then + NO_MANAGER=true +fi + +if [[ ${BOOTMODE} == true && ${NO_MANAGER} == true ]]; then + ui_print "- Installing stub apk" + ${ENFORCE} && setenforce 0 + (pm install "${MODPATH}/EdXposed.apk" >/dev/null 2>&2) || ui_print " - Stub install failed! Do not forget install EdXposed Manager manually" + ${ENFORCE} && setenforce 1 +fi + +if [[ "${OLD_MAGISK}" == true ]]; then + ui_print "- Removing SEPolicy rule for old Magisk" + rm "${MODPATH}"/sepolicy.rule +fi + +#echo "- Mounted persist:" >&2 +#mount | grep persist >&2 + +#if [[ "${NO_PERSIST}" == true ]]; then +# ui_print "- Persist not detected, remove SEPolicy rule" +# rm ${MODPATH}/sepolicy.rule +#fi + +ui_print "- Copying framework libraries" + +mv "${MODPATH}/system/framework/eddalvikdx.jar" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}" +mv "${MODPATH}/system/framework/edxp.jar" "${MODPATH}/system/framework/${JAR_EDXP}" +mv "${MODPATH}/system/framework/eddexmaker.jar" "${MODPATH}/system/framework/${JAR_EDDEXMAKER}" +mv "${MODPATH}/system/framework/edconfig.jar" "${MODPATH}/system/framework/${JAR_EDCONFIG}" +mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" +mv "${MODPATH}/system/lib/libwhale.edxp.so" "${MODPATH}/system/lib/${LIB_WHALE_EDXP}" + +if [[ "${IS64BIT}" == true ]]; then + mv "${MODPATH}/system/lib64/libriru_edxp.so" "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" + mv "${MODPATH}/system/lib64/libwhale.edxp.so" "${MODPATH}/system/lib64/${LIB_WHALE_EDXP}" +fi + +if [[ "${VARIANTS}" == "SandHook" ]]; then + mv "${MODPATH}/system/lib/libsandhook.edxp.so" "${MODPATH}/system/lib/${LIB_SANDHOOK_EDXP}" + if [[ "${IS64BIT}" == true ]]; then + mv "${MODPATH}/system/lib64/libsandhook.edxp.so" "${MODPATH}/system/lib64/${LIB_SANDHOOK_EDXP}" + fi +fi + +ui_print "- Resetting libraries path" + +sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" +sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" +sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" +sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" +sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}" + +if [[ "${IS64BIT}" == true ]]; then + sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" + sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" + sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" + sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" + sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}" +fi + +ui_print "- Removing old configuration" + +if [[ -f "${RIRU_MODULES}/edxp.prop" ]]; then + OLD_CONFIG=$(cat "${RIRU_MODULES}/edxp.prop") + rm -rf "${RIRU_MODULES}/${OLD_CONFIG}" +fi + +if [[ -e "${RIRU_MODULES}/edxp" ]]; then + rm -rf "${RIRU_MODULES}/edxp" +fi + +ui_print "- Copying extra files" + +[[ -d "${RIRU_TARGET}" ]] || mkdir -p "${RIRU_TARGET}" || abort "! Can't mkdir -p ${RIRU_TARGET}" + +echo "${RIRU_EDXP}">"${RIRU_MODULES}/edxp.prop" + +rm "${RIRU_TARGET}/module.prop" + +cp "${MODPATH}/module.prop" "${RIRU_TARGET}/module.prop" || abort "! Can't create ${RIRU_TARGET}/module.prop" + +set_perm_recursive "${MODPATH}" 0 0 0755 0644 + +ui_print "- Welcome to EdXposed ${VERSION}!" \ No newline at end of file diff --git a/edxp-core/template_override/install.sh b/edxp-core/template_override/install.sh deleted file mode 100644 index 80e55319..00000000 --- a/edxp-core/template_override/install.sh +++ /dev/null @@ -1,186 +0,0 @@ -########################################################################################## -# -# Magisk Module Installer Script -# -########################################################################################## -########################################################################################## -# -# Instructions: -# -# 1. Place your files into system folder (delete the placeholder file) -# 2. Fill in your module's info into module.prop -# 3. Configure and implement callbacks in this file -# 4. If you need boot scripts, add them into common/post-fs-data.sh or common/service.sh -# 5. Add your additional or modified system properties into common/system.prop -# -########################################################################################## - - ########################################################################################## -# Config Flags -########################################################################################## - - # Set to true if you do *NOT* want Magisk to mount -# any files for you. Most modules would NOT want -# to set this flag to true -SKIPMOUNT=false - - # Set to true if you need to load system.prop -PROPFILE=true - - # Set to true if you need post-fs-data script -POSTFSDATA=true - - # Set to true if you need late_start service script -LATESTARTSERVICE=false - - ########################################################################################## -# Replace list -########################################################################################## - - # List all directories you want to directly replace in the system -# Check the documentations for more info why you would need this - - # Construct your list in the following format -# This is an example -REPLACE_EXAMPLE=" -/system/app/Youtube -/system/priv-app/SystemUI -/system/priv-app/Settings -/system/framework -" - - # Construct your own list here -REPLACE=" -" - - ########################################################################################## -# -# Function Callbacks -# -# The following functions will be called by the installation framework. -# You do not have the ability to modify update-binary, the only way you can customize -# installation is through implementing these functions. -# -# When running your callbacks, the installation framework will make sure the Magisk -# internal busybox path is *PREPENDED* to PATH, so all common commands shall exist. -# Also, it will make sure /data, /system, and /vendor is properly mounted. -# -########################################################################################## -########################################################################################## -# -# The installation framework will export some variables and functions. -# You should use these variables and functions for installation. -# -# ! DO NOT use any Magisk internal paths as those are NOT public API. -# ! DO NOT use other functions in util_functions.sh as they are NOT public API. -# ! Non public APIs are not guranteed to maintain compatibility between releases. -# -# Available variables: -# -# MAGISK_VER (string): the version string of current installed Magisk -# MAGISK_VER_CODE (int): the version code of current installed Magisk -# BOOTMODE (bool): true if the module is currently installing in Magisk Manager -# MODPATH (path): the path where your module files should be installed -# TMPDIR (path): a place where you can temporarily store files -# ZIPFILE (path): your module's installation zip -# ARCH (string): the architecture of the device. Value is either arm, arm64, x86, or x64 -# IS64BIT (bool): true if $ARCH is either arm64 or x64 -# API (int): the API level (Android version) of the device -# -# Availible functions: -# -# ui_print -# print to console -# Avoid using 'echo' as it will not display in custom recovery's console -# -# abort -# print error message to console and terminate installation -# Avoid using 'exit' as it will skip the termination cleanup steps -# -# set_perm [context] -# if [context] is empty, it will default to "u:object_r:system_file:s0" -# this function is a shorthand for the following commands -# chown owner.group target -# chmod permission target -# chcon context target -# -# set_perm_recursive [context] -# if [context] is empty, it will default to "u:object_r:system_file:s0" -# for all files in , it will call: -# set_perm file owner group filepermission context -# for all directories in (including itself), it will call: -# set_perm dir owner group dirpermission context -# -########################################################################################## -########################################################################################## -# If you need boot scripts, DO NOT use general boot scripts (post-fs-data.d/service.d) -# ONLY use module scripts as it respects the module status (remove/disable) and is -# guaranteed to maintain the same behavior in future Magisk releases. -# Enable boot scripts by setting the flags in the config section above. -########################################################################################## - - RIRU_PATH="/data/misc/riru" - - print_modname() { - ui_print "*******************************" - ui_print "* Riru - EdXposed *" - ui_print "*******************************" -} - - check_riru_version() { - [[ ! -f "$RIRU_PATH/api_version" ]] && abort "! Please Install Riru - Core v19 or above" - VERSION=$(cat "$RIRU_PATH/api_version") - ui_print "- Riru API version is $VERSION" - [[ "$VERSION" -ge 4 ]] || abort "! Please Install Riru - Core v19 or above" -} - - check_architecture() { - if [[ "$ARCH" != "arm" && "$ARCH" != "arm64" && "$ARCH" != "x86" && "$ARCH" != "x64" ]]; then - abort "! Unsupported platform: $ARCH" - else - ui_print "- Device platform: $ARCH" - fi -} - - on_install() { - check_architecture - check_riru_version - - if [[ "$ARCH" == "x86" || "$ARCH" == "x64" ]]; then - ui_print "- Extracting x86/64 libraries" - unzip -o "$ZIPFILE" 'system_x86/*' -d $MODPATH >&2 - mv "$MODPATH/system_x86/lib" "$MODPATH/system/lib" - mv "$MODPATH/system_x86/lib64" "$MODPATH/system/lib64" - else - ui_print "- Extracting arm/arm64 libraries" - unzip -o "$ZIPFILE" 'system/*' -d $MODPATH >&2 - fi - - if [[ "$IS64BIT" = false ]]; then - ui_print "- Removing 64-bit libraries" - rm -rf "$MODPATH/system/lib64" - fi - - TARGET="$RIRU_PATH/modules" - - ui_print "- Extracting extra files" - unzip -o "$ZIPFILE" 'data/*' -d "$TMPDIR" >&2 - - [[ -d "$TARGET" ]] || mkdir -p "$TARGET" || abort "! Can't mkdir -p $TARGET" - cp -af "$TMPDIR$TARGET/." "$TARGET" || abort "! Can't cp -af $TMPDIR$TARGET/. $TARGET" - - cp -af "$TMPDIR/util_functions.sh" "$MODPATH/util_functions.sh" || abort "! Can't cp -af $TMPDIR/util_functions.sh $MODPATH/util_functions.sh" - - ui_print "- Files copied" -} - - set_permissions() { - # The following is the default rule, DO NOT remove - set_perm_recursive $MODPATH 0 0 0755 0644 - - # Here are some examples: - # set_perm_recursive $MODPATH/system/lib 0 0 0755 0644 - # set_perm $MODPATH/system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0 - # set_perm $MODPATH/system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0 - # set_perm $MODPATH/system/lib/libart.so 0 0 0644 -} diff --git a/edxp-core/template_override/post-fs-data.sh b/edxp-core/template_override/post-fs-data.sh new file mode 100644 index 00000000..e3b1b2ac --- /dev/null +++ b/edxp-core/template_override/post-fs-data.sh @@ -0,0 +1,170 @@ +#!/system/bin/sh + +grep_prop() { + local REGEX="s/^$1=//p" + shift + local FILES=$@ + [[ -z "$FILES" ]] && FILES='/system/build.prop' + sed -n "$REGEX" ${FILES} 2>/dev/null | head -n 1 +} + +MODDIR=${0%/*} + +RIRU_PATH="/data/misc/riru" +TARGET="${RIRU_PATH}/modules" +[[ "$(getenforce)" == "Enforcing" ]] && ENFORCE=true || ENFORCE=false + +EDXP_VERSION=$(grep_prop version "${MODDIR}/module.prop") + +ANDROID_SDK=$(getprop ro.build.version.sdk) +BUILD_DESC=$(getprop ro.build.description) +PRODUCT=$(getprop ro.build.product) +MODEL=$(getprop ro.product.model) +MANUFACTURER=$(getprop ro.product.manufacturer) +BRAND=$(getprop ro.product.brand) +FINGERPRINT=$(getprop ro.build.fingerprint) +ARCH=$(getprop ro.product.cpu.abi) +DEVICE=$(getprop ro.product.device) +ANDROID=$(getprop ro.build.version.release) +BUILD=$(getprop ro.build.id) + +RIRU_VERSION=$(cat "${RIRU_PATH}/version_name") +RIRU_VERCODE=$(cat "${RIRU_PATH}/version_code") +RIRU_APICODE=$(cat "${RIRU_PATH}/api_version") + +MAGISK_VERSION=$(su -v) +MAGISK_VERCODE=$(su -V) + +EDXP_MANAGER="org.meowcat.edxposed.manager" +XP_INSTALLER="de.robv.android.xposed.installer" +PATH_PREFIX="/data/user_de/0/" +#PATH_PREFIX_LEGACY="/data/user/0/" + +sepolicy() { + # necessary for using mmap in system_server process + # read configs set in our app + # for built-in apps // TODO: maybe narrow down the target classes + # read module apk file in zygote + # TODO: remove coredomain sepolicy + supolicy --live "allow system_server system_server process { execmem }"\ + "allow system_server system_server memprotect { mmap_zero }"\ + "allow coredomain coredomain process { execmem }"\ + "allow coredomain app_data_file * *"\ + "attradd { system_app platform_app } mlstrustedsubject"\ + "allow zygote apk_data_file * *" +} + +#if [[ ${ANDROID_SDK} -ge 24 ]]; then +# PATH_PREFIX="${PATH_PREFIX_PROT}" +#else +# PATH_PREFIX="${PATH_PREFIX_LEGACY}" +#fi + +DEFAULT_BASE_PATH="${PATH_PREFIX}${EDXP_MANAGER}" +BASE_PATH="${DEFAULT_BASE_PATH}" + +if [[ ! -d ${BASE_PATH} ]]; then + BASE_PATH="${PATH_PREFIX}${XP_INSTALLER}" + if [[ ! -d ${BASE_PATH} ]]; then + BASE_PATH="${DEFAULT_BASE_PATH}" + fi +fi + +LOG_PATH="${BASE_PATH}/log" +CONF_PATH="${BASE_PATH}/conf" +DISABLE_VERBOSE_LOG_FILE="${CONF_PATH}/disable_verbose_log" +LOG_VERBOSE=true +OLD_PATH=${PATH} +PATH=${PATH#*:} +PATH_INFO=$(ls -ldZ "${BASE_PATH}") +PATH=${OLD_PATH} +PATH_OWNER=$(echo "${PATH_INFO}" | awk -F " " '{print $3":"$4}') +PATH_CONTEXT=$(echo "${PATH_INFO}" | awk -F " " '{print $5}') + +if [[ -f ${DISABLE_VERBOSE_LOG_FILE} ]]; then + LOG_VERBOSE=false +fi + +start_log_cather () { + LOG_FILE_NAME=$1 + LOG_TAG_FILTERS=$2 + CLEAN_OLD=$3 + START_NEW=$4 + LOG_FILE="${LOG_PATH}/${LOG_FILE_NAME}.log" + PID_FILE="${LOG_PATH}/${LOG_FILE_NAME}.pid" + mkdir -p ${LOG_PATH} + if [[ ${CLEAN_OLD} == true ]]; then + rm "${LOG_FILE}.old" + mv "${LOG_FILE}" "${LOG_FILE}.old" + fi + rm "${LOG_PATH}/${LOG_FILE_NAME}.pid" + if [[ ${START_NEW} == false ]]; then + return + fi + touch ${LOG_FILE} + touch ${PID_FILE} + echo "--------- beginning of head">>${LOG_FILE} + echo "EdXposed Log">>${LOG_FILE} + echo "Powered by Log Catcher">>${LOG_FILE} + echo "QQ support group: 855219808">>${LOG_FILE} + echo "Telegram support group: @Code_Of_MeowCat">>${LOG_FILE} + echo "Telegram channel: @EdXposed">>${LOG_FILE} + echo "--------- beginning of information">>${LOG_FILE} + echo "Manufacturer: ${MANUFACTURER}">>${LOG_FILE} + echo "Brand: ${BRAND}">>${LOG_FILE} + echo "Device: ${DEVICE}">>${LOG_FILE} + echo "Product: ${PRODUCT}">>${LOG_FILE} + echo "Model: ${MODEL}">>${LOG_FILE} + echo "Fingerprint: ${FINGERPRINT}">>${LOG_FILE} + echo "ROM description: ${BUILD_DESC}">>${LOG_FILE} + echo "Architecture: ${ARCH}">>${LOG_FILE} + echo "Android build: ${BUILD}">>${LOG_FILE} + echo "Android version: ${ANDROID}">>${LOG_FILE} + echo "Android sdk: ${ANDROID_SDK}">>${LOG_FILE} + echo "EdXposed version: ${EDXP_VERSION}">>${LOG_FILE} + echo "EdXposed api: 91.0">>${LOG_FILE} + echo "Riru version: ${RIRU_VERSION} (${RIRU_VERCODE})">>${LOG_FILE} + echo "Riru api: ${RIRU_APICODE}">>${LOG_FILE} + echo "Magisk: ${MAGISK_VERSION%:*} (${MAGISK_VERCODE})">>${LOG_FILE} + logcat -f ${LOG_FILE} *:S ${LOG_TAG_FILTERS} & + LOG_PID=$! + echo "${LOG_PID}">"${LOG_PATH}/${LOG_FILE_NAME}.pid" +} + +# Backup app_process to avoid bootloop caused by original Xposed replacement in Android Oreo +# TODO: Magisk mount replace +rm -rf "${MODDIR}/system/bin" +mkdir "${MODDIR}/system/bin" +cp -f "/system/bin/app_process32" "${MODDIR}/system/bin/app_process32" +[[ -f "/system/bin/app_process64" ]] && cp -f "/system/bin/app_process64" "${MODDIR}/system/bin/app_process64" + +# install stub if manager not installed +if [[ "$(pm path org.meowcat.edxposed.manager)" == "" && "$(pm path de.robv.android.xposed.installer)" == "" ]]; then + NO_MANAGER=true +fi +if [[ ${NO_MANAGER} == true ]]; then + ${ENFORCE} && setenforce 0 + pm install "${MODDIR}/EdXposed.apk" + ${ENFORCE} && setenforce 1 +fi + +# execute live patch if rule not found +[[ -f "${MODDIR}/sepolicy.rule" ]] || sepolicy + +# start_verbose_log_catcher +start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE} + +# start_bridge_log_catcher +start_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true + + +if [[ -f "/data/misc/riru/modules/edxp.prop" ]]; then + CONFIG=$(cat "/data/misc/riru/modules/edxp.prop") + [[ -d "${TARGET}/${CONFIG}" ]] || mkdir -p "${TARGET}/${CONFIG}" + cp "${MODDIR}/module.prop" "${TARGET}/${CONFIG}/module.prop" +fi + +chcon -R u:object_r:system_file:s0 "${MODDIR}" +chcon -R ${PATH_CONTEXT} "${LOG_PATH}" +chown -R ${PATH_OWNER} "${LOG_PATH}" +chmod -R 666 "${LOG_PATH}" \ No newline at end of file diff --git a/edxp-core/template_override/sepolicy.rule b/edxp-core/template_override/sepolicy.rule new file mode 100644 index 00000000..3b02a68c --- /dev/null +++ b/edxp-core/template_override/sepolicy.rule @@ -0,0 +1,6 @@ +allow system_server system_server process {execmem} +allow system_server system_server memprotect {mmap_zero} +allow coredomain coredomain process {execmem} +allow coredomain app_data_file * * +attradd {system_app platform_app} mlstrustedsubject +allow zygote apk_data_file * * diff --git a/edxp-core/template_override/common/system.prop b/edxp-core/template_override/system.prop similarity index 100% rename from edxp-core/template_override/common/system.prop rename to edxp-core/template_override/system.prop diff --git a/edxp-core/template_override/uninstall.sh b/edxp-core/template_override/uninstall.sh index 6ec47ab8..9710469f 100644 --- a/edxp-core/template_override/uninstall.sh +++ b/edxp-core/template_override/uninstall.sh @@ -1,4 +1,24 @@ #!/sbin/sh -#rm -r -f /data/misc/riru/modules/edxposed/ -#rm -r -f /data/misc/riru/modules/edxp/ +MODDIR=${0%/*} +VARIANT="YAHFA" +REMOVE=false + +[[ "$(echo ${MODDIR} | grep sandhook)" != "" ]] && VARIANT="SandHook" + +if [[ "${VARIANT}" == "SandHook" ]]; then + [[ -f "${MODDIR}/../riru_edxposed/module.prop" ]] || REMOVE=true +else + [[ -f "${MODDIR}/../riru_edxposed_sandhook/module.prop" ]] || REMOVE=true +fi + +if [[ "${REMOVE}" == true ]]; then + rm -rf /data/misc/riru/modules/edxp + if [[ -f "/data/misc/riru/modules/edxp.prop" ]]; then + OLD_CONFIG=$(cat "/data/misc/riru/modules/edxp.prop") + rm -rf "/data/misc/riru/modules/${OLD_CONFIG}" + rm "/data/misc/riru/modules/edxp.prop" + fi +fi + + diff --git a/edxp-core/tpl/edconfig.tpl b/edxp-core/tpl/edconfig.tpl index c5abe46c..922618cd 100644 --- a/edxp-core/tpl/edconfig.tpl +++ b/edxp-core/tpl/edconfig.tpl @@ -1,5 +1,5 @@ -version=90.0-$version ($backend) +version=91.0-$version ($backend) arch=arm64 minsdk=26 -maxsdk=28 +maxsdk=29 requires:fbe_aware=1 diff --git a/edxp-core/tpl/module.prop.tpl b/edxp-core/tpl/module.prop.tpl index 6ca8d5bc..6f22cd1f 100644 --- a/edxp-core/tpl/module.prop.tpl +++ b/edxp-core/tpl/module.prop.tpl @@ -3,5 +3,5 @@ name=Riru - EdXposed version=${versionName} versionCode=${versionCode} author=${authorList} -description=Magisk version of Xposed. Require Riru - Core v19+ installed. See change log in EdXposed Manager or Github Releases. +description=Another enhanced implementation of Xposed Framework. Supports Android 8.0, 8.1, 9, 10 or above. Requires Riru - Core v19 or above installed. Telegram: @EdXposed api=4 diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java index 4ec3f91a..5464a5a3 100644 --- a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/SandHookEdxpImpl.java @@ -2,8 +2,6 @@ package com.elderdrivers.riru.edxp.sandhook.core; import android.os.Build; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.InstallerChooser; import com.elderdrivers.riru.edxp.core.BaseEdxpImpl; import com.elderdrivers.riru.edxp.core.EdxpImpl; import com.elderdrivers.riru.edxp.core.Main; @@ -36,9 +34,7 @@ public class SandHookEdxpImpl extends BaseEdxpImpl { Yahfa.init(Build.VERSION.SDK_INT); HookMethodResolver.init(); getRouter().injectConfig(); - InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName()); SandHookXposedBridge.init(); - setInitialized(); } } diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java index ba9605cb..1ec8b1f8 100644 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java @@ -1,24 +1,22 @@ package com.swift.sandhook.xposedcompat; -import android.annotation.SuppressLint; import android.os.Process; import android.text.TextUtils; import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.util.ComposeClassLoader; +import com.elderdrivers.riru.edxp.util.FileUtils; +import com.elderdrivers.riru.edxp.util.ProcessUtils; +import com.elderdrivers.riru.edxp.util.ProxyClassLoader; import com.swift.sandhook.wrapper.HookWrapper; import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; import com.swift.sandhook.xposedcompat.utils.ApplicationUtils; -import com.swift.sandhook.xposedcompat.utils.FileUtils; -import com.swift.sandhook.xposedcompat.utils.ProcessUtils; import java.io.File; import java.lang.reflect.Member; import de.robv.android.xposed.XposedBridge; -import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE; -import static com.swift.sandhook.xposedcompat.utils.FileUtils.IS_USING_PROTECTED_STORAGE; +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; public class XposedCompat { @@ -54,7 +52,7 @@ public class XposedCompat { if (cacheDir == null) { String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/"; cacheDir = new File(fixedAppDataDir, "/cache/sandhook/" - + ProcessUtils.getProcessName().replace(":", "_") + "/"); + + ProcessUtils.getProcessName(Process.myPid()).replace(":", "_") + "/"); } return cacheDir; } @@ -74,7 +72,7 @@ public class XposedCompat { if (sandHookXposedClassLoader != null) { return sandHookXposedClassLoader; } else { - sandHookXposedClassLoader = new ComposeClassLoader(sandBoxHostClassLoader, appOriginClassLoader); + sandHookXposedClassLoader = new ProxyClassLoader(sandBoxHostClassLoader, appOriginClassLoader); return sandHookXposedClassLoader; } } @@ -104,12 +102,4 @@ public class XposedCompat { return dataDir.substring(lastIndex + 1); } - // FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet. - @SuppressLint("SdCardPath") - public static String getDataPathPrefix() { - int userId = Process.myUid() / PER_USER_RANGE; - String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/"; - return String.format(format, userId); - } - } diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java index 2bdf3e99..eb7e80cf 100644 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java @@ -244,6 +244,11 @@ public class HookStubManager { args = entity.getArgs(stubArgs); } + if (thiz == null) + { + thiz = originMethod.getDeclaringClass(); + } + if (XposedBridge.disableHooks) { if (hasStubBackup) { return callOrigin.call(stubArgs); @@ -351,6 +356,7 @@ public class HookStubManager { try { ((XC_MethodHook) snapshot[beforeIdx]).callBeforeHookedMethod(param); } catch (Throwable t) { + XposedBridge.log(t); // reset result (ignoring what the unexpectedly exiting callback did) param.setResult(null); param.returnEarly = false; diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java index 803dd131..c157598d 100644 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java @@ -5,7 +5,9 @@ import android.os.Process; import android.os.Trace; import android.util.Log; +import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.util.ClassLoaderUtils; +import com.elderdrivers.riru.edxp.util.FileUtils; import com.swift.sandhook.SandHook; import com.swift.sandhook.SandHookConfig; import com.swift.sandhook.blacklist.HookBlackList; @@ -14,7 +16,6 @@ import com.swift.sandhook.xposedcompat.XposedCompat; import com.swift.sandhook.xposedcompat.hookstub.HookMethodEntity; import com.swift.sandhook.xposedcompat.hookstub.HookStubManager; import com.swift.sandhook.xposedcompat.utils.DexLog; -import com.swift.sandhook.xposedcompat.utils.FileUtils; import java.io.File; import java.lang.reflect.Constructor; @@ -84,7 +85,7 @@ public final class SandHookXposedBridge { hookMaker = defaultHookMaker; } hookMaker.start(hookMethod, additionalHookInfo, - ClassLoaderUtils.createComposeClassLoader( + ClassLoaderUtils.createProxyClassLoader( hookMethod.getDeclaringClass().getClassLoader()), dexDir == null ? null : dexDir.getAbsolutePath()); hookedInfo.put(hookMethod, hookMaker.getCallBackupMethod()); @@ -133,9 +134,11 @@ public final class SandHookXposedBridge { public static void init() { if (Process.is64Bit()) { - SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so"; +// SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so"; + SandHookConfig.libSandHookPath = "/system/lib64/" + ConfigManager.getLibSandHookName(); } else { - SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so"; +// SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so"; + SandHookConfig.libSandHookPath = "/system/lib/" + ConfigManager.getLibSandHookName(); } SandHookConfig.libLoader = new SandHookConfig.LibLoader() { @Override diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java deleted file mode 100644 index 4acfa841..00000000 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.swift.sandhook.xposedcompat.utils; - -import android.os.Build; -import android.util.ArrayMap; - -import com.elderdrivers.riru.edxp.sandhook.BuildConfig; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import dalvik.system.PathClassLoader; - -public class ClassLoaderUtils { - - public static final String DEXPATH = "/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex"; - - public static void replaceParentClassLoader(ClassLoader appClassLoader) { - if (appClassLoader == null) { - DexLog.e("appClassLoader is null, you might be kidding me?"); - return; - } - try { - ClassLoader curCL = ClassLoaderUtils.class.getClassLoader(); - ClassLoader parent = appClassLoader; - ClassLoader lastChild = appClassLoader; - while (parent != null) { - ClassLoader tmp = parent.getParent(); - if (tmp == curCL) { - DexLog.d("replacing has been done before, skip."); - return; - } - if (tmp == null) { - DexLog.d("before replacing =========================================>"); - dumpClassLoaders(appClassLoader); - Field parentField = ClassLoader.class.getDeclaredField("parent"); - parentField.setAccessible(true); - parentField.set(curCL, parent); - parentField.set(lastChild, curCL); - DexLog.d("after replacing ==========================================>"); - dumpClassLoaders(appClassLoader); - } - lastChild = parent; - parent = tmp; - } - } catch (Throwable throwable) { - DexLog.e("error when replacing class loader.", throwable); - } - } - - private static void dumpClassLoaders(ClassLoader classLoader) { - if (BuildConfig.DEBUG) { - while (classLoader != null) { - DexLog.d(classLoader + " =>"); - classLoader = classLoader.getParent(); - } - } - } - - public static List getAppClassLoader() { - List cacheLoaders = new ArrayList<>(0); - try { - DexLog.d("start getting app classloader"); - Class appLoadersClass = Class.forName("android.app.ApplicationLoaders"); - Field loadersField = appLoadersClass.getDeclaredField("gApplicationLoaders"); - loadersField.setAccessible(true); - Object loaders = loadersField.get(null); - Field mLoaderMapField = loaders.getClass().getDeclaredField("mLoaders"); - mLoaderMapField.setAccessible(true); - ArrayMap mLoaderMap = (ArrayMap) mLoaderMapField.get(loaders); - DexLog.d("mLoaders size = " + mLoaderMap.size()); - cacheLoaders = new ArrayList<>(mLoaderMap.values()); - } catch (Exception ex) { - DexLog.e("error get app class loader.", ex); - } - return cacheLoaders; - } - - private static HashSet classLoaders = new HashSet<>(); - - public static boolean addPathToClassLoader(ClassLoader classLoader) { - if (!(classLoader instanceof PathClassLoader)) { - DexLog.w(classLoader + " is not a BaseDexClassLoader!!!"); - return false; - } - if (classLoaders.contains(classLoader)) { - DexLog.d(classLoader + " has been hooked before"); - return true; - } - try { - PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - //baseDexClassLoader.addDexPath(DEXPATH); - } else { - DexUtils.injectDexAtFirst(DEXPATH, baseDexClassLoader); - } - classLoaders.add(classLoader); - return true; - } catch (Throwable throwable) { - DexLog.e("error when addPath to ClassLoader: " + classLoader, throwable); - } - return false; - } - -} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java deleted file mode 100644 index 55bd02f4..00000000 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.swift.sandhook.xposedcompat.utils; - -import android.annotation.TargetApi; -import android.os.Build; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; - -import dalvik.system.BaseDexClassLoader; -import dalvik.system.DexClassLoader; - -/** - * For 6.0 only. - */ -@TargetApi(Build.VERSION_CODES.M) -public class DexUtils { - - public static void injectDexAtFirst(String dexPath, BaseDexClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { - DexClassLoader dexClassLoader = new DexClassLoader(dexPath, null, dexPath, classLoader); - Object baseDexElements = getDexElements(getPathList(classLoader)); - Object newDexElements = getDexElements(getPathList(dexClassLoader)); - Object allDexElements = combineArray(newDexElements, baseDexElements); - Object pathList = getPathList(classLoader); - setField(pathList, pathList.getClass(), "dexElements", allDexElements); - } - - private static Object getDexElements(Object paramObject) - throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException { - return getField(paramObject, paramObject.getClass(), "dexElements"); - } - - private static Object getPathList(Object baseDexClassLoader) - throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException { - return getField(baseDexClassLoader, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList"); - } - - private static Object combineArray(Object firstArray, Object secondArray) { - Class localClass = firstArray.getClass().getComponentType(); - int firstArrayLength = Array.getLength(firstArray); - int allLength = firstArrayLength + Array.getLength(secondArray); - Object result = Array.newInstance(localClass, allLength); - for (int k = 0; k < allLength; ++k) { - if (k < firstArrayLength) { - Array.set(result, k, Array.get(firstArray, k)); - } else { - Array.set(result, k, Array.get(secondArray, k - firstArrayLength)); - } - } - return result; - } - - public static Object getField(Object obj, Class cl, String field) - throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { - Field localField = cl.getDeclaredField(field); - localField.setAccessible(true); - return localField.get(obj); - } - - public static void setField(Object obj, Class cl, String field, Object value) - throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { - Field localField = cl.getDeclaredField(field); - localField.setAccessible(true); - localField.set(obj, value); - } - -} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java deleted file mode 100644 index c3c7acc1..00000000 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.swift.sandhook.xposedcompat.utils; - -import android.os.Build; -import android.text.TextUtils; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; - -public class FileUtils { - - public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; - - /** - * Delete a file or a directory and its children. - * - * @param file The directory to delete. - * @throws IOException Exception when problem occurs during deleting the directory. - */ - public static void delete(File file) throws IOException { - - for (File childFile : file.listFiles()) { - - if (childFile.isDirectory()) { - delete(childFile); - } else { - if (!childFile.delete()) { - throw new IOException(); - } - } - } - - if (!file.delete()) { - throw new IOException(); - } - } - - public static String readLine(File file) { - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - return reader.readLine(); - } catch (Throwable throwable) { - return ""; - } - } - - public static void writeLine(File file, String line) { - try { - file.createNewFile(); - } catch (IOException ex) { - } - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - writer.write(line); - writer.flush(); - } catch (Throwable throwable) { - DexLog.e("error writing line to file " + file + ": " + throwable.getMessage()); - } - } - - public static String getPackageName(String dataDir) { - if (TextUtils.isEmpty(dataDir)) { - DexLog.e("getPackageName using empty dataDir"); - return ""; - } - int lastIndex = dataDir.lastIndexOf("/"); - if (lastIndex < 0) { - return dataDir; - } - return dataDir.substring(lastIndex + 1); - } - - public static String getDataPathPrefix() { - return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/"; - } -} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java deleted file mode 100644 index a401298a..00000000 --- a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.swift.sandhook.xposedcompat.utils; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.Process; -import android.text.TextUtils; - -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by swift_gan on 2017/11/23. - */ - -public class ProcessUtils { - - public static String getProcessName() { - return getProcessName(Process.myPid()); - } - - private static String doGetProcessName(Context context) { - ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - List runningApps = am.getRunningAppProcesses(); - if (runningApps == null) { - return null; - } - for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) { - if (proInfo.pid == android.os.Process.myPid()) { - if (proInfo.processName != null) { - return proInfo.processName; - } - } - } - return context.getPackageName(); - } - - public static String getProcessName(int pid) { - BufferedReader cmdlineReader = null; - try { - cmdlineReader = new BufferedReader(new InputStreamReader( - new FileInputStream( - "/proc/" + pid + "/cmdline"), - "iso-8859-1")); - int c; - StringBuilder processName = new StringBuilder(); - while ((c = cmdlineReader.read()) > 0) { - processName.append((char) c); - } - return processName.toString(); - } catch (Throwable throwable) { - DexLog.w("getProcessName: " + throwable.getMessage()); - } finally { - try { - if (cmdlineReader != null) { - cmdlineReader.close(); - } - } catch (Throwable throwable) { - DexLog.e("getProcessName: " + throwable.getMessage()); - } - } - return ""; - } - - public static boolean isMainProcess(Context context) { - String processName = getProcessName(); - String pkgName = context.getPackageName(); - if (!TextUtils.isEmpty(processName) && !TextUtils.equals(processName, pkgName)) { - return false; - } else { - return true; - } - } - - public static List findActivitiesForPackage(Context context, String packageName) { - final PackageManager packageManager = context.getPackageManager(); - - final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - mainIntent.setPackage(packageName); - - final List apps = packageManager.queryIntentActivities(mainIntent, 0); - return apps != null ? apps : new ArrayList(); - } -} diff --git a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleEdxpImpl.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleEdxpImpl.java index 5f645b77..be000b0c 100644 --- a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleEdxpImpl.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleEdxpImpl.java @@ -2,12 +2,9 @@ package com.elderdrivers.riru.edxp.whale.core; import android.os.Build; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.InstallerChooser; import com.elderdrivers.riru.edxp.core.BaseEdxpImpl; import com.elderdrivers.riru.edxp.core.EdxpImpl; import com.elderdrivers.riru.edxp.core.Main; -import com.elderdrivers.riru.edxp.core.Proxy; import com.elderdrivers.riru.edxp.core.Yahfa; import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver; import com.elderdrivers.riru.edxp.proxy.Router; @@ -36,8 +33,6 @@ public class WhaleEdxpImpl extends BaseEdxpImpl { Yahfa.init(Build.VERSION.SDK_INT); HookMethodResolver.init(); getRouter().injectConfig(); - InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName()); - setInitialized(); } diff --git a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleRouter.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleRouter.java index 37940496..e58290d3 100644 --- a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleRouter.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/whale/core/WhaleRouter.java @@ -1,5 +1,6 @@ package com.elderdrivers.riru.edxp.whale.core; +import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import com.elderdrivers.riru.edxp.framework.Zygote; import com.elderdrivers.riru.edxp.proxy.BaseRouter; @@ -16,8 +17,10 @@ public class WhaleRouter extends BaseRouter { BaseRouter.useXposedApi = true; EdXpConfigGlobal.sConfig = new WhaleEdxpConfig(); EdXpConfigGlobal.sHookProvider = new WhaleHookProvider(); - Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so"); - Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so"); +// Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so"); +// Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so"); + Zygote.allowFileAcrossFork("/system/lib/" + ConfigManager.getLibWhaleName()); + Zygote.allowFileAcrossFork("/system/lib64/" + ConfigManager.getLibWhaleName()); Zygote.allowFileAcrossFork("/system/lib/libart.so"); Zygote.allowFileAcrossFork("/system/lib64/libart.so"); } diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java index da225aa7..8a05b27d 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/YahfaEdxpImpl.java @@ -2,8 +2,6 @@ package com.elderdrivers.riru.edxp.yahfa.core; import android.os.Build; -import com.elderdrivers.riru.edxp.config.ConfigManager; -import com.elderdrivers.riru.edxp.config.InstallerChooser; import com.elderdrivers.riru.edxp.core.BaseEdxpImpl; import com.elderdrivers.riru.edxp.core.EdxpImpl; import com.elderdrivers.riru.edxp.core.Main; @@ -34,8 +32,6 @@ public class YahfaEdxpImpl extends BaseEdxpImpl { Yahfa.init(Build.VERSION.SDK_INT); HookMethodResolver.init(); getRouter().injectConfig(); - InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName()); - setInitialized(); } diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java index 421b4051..c184bf4b 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java @@ -6,7 +6,7 @@ import android.text.TextUtils; import com.elderdrivers.riru.edxp.core.Yahfa; import com.elderdrivers.riru.edxp.core.yahfa.HookMain; -import com.elderdrivers.riru.edxp.util.ComposeClassLoader; +import com.elderdrivers.riru.edxp.util.ProxyClassLoader; import java.io.File; import java.lang.reflect.Constructor; @@ -181,7 +181,7 @@ public class HookerDexMaker { mAppClassLoader = getClass().getClassLoader(); } else { mAppClassLoader = appClassLoader; - mAppClassLoader = new ComposeClassLoader(mAppClassLoader, getClass().getClassLoader()); + mAppClassLoader = new ProxyClassLoader(mAppClassLoader, getClass().getClassLoader()); } doMake(); } diff --git a/xposed-bridge/src/main/java/android/content/res/XResources.java b/xposed-bridge/src/main/java/android/content/res/XResources.java index 8de7c840..ae73428f 100644 --- a/xposed-bridge/src/main/java/android/content/res/XResources.java +++ b/xposed-bridge/src/main/java/android/content/res/XResources.java @@ -8,6 +8,7 @@ import android.graphics.Movie; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.StrictMode; import android.text.Html; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -115,8 +116,10 @@ public class XResources extends XResourcesSuperClass { if (mResDir == null) return false; + final StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads(); Long lastModification = new File(mResDir).lastModified(); Long oldModified = sResDirLastModified.get(mResDir); + StrictMode.setThreadPolicy(policy); if (lastModification.equals(oldModified)) return false; diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java index 4a12da20..a8959cfd 100644 --- a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdxpConfig.java @@ -2,12 +2,22 @@ package com.elderdrivers.riru.edxp.config; public interface EdxpConfig { - String getInstallerBaseDir(); + String getInstallerConfigPath(String suffix); - String getBlackListModulePackageName(); + String getDataPathPrefix(); + + String getInstallerPackageName(); + + String getXposedPropPath(); + + String getLibSandHookName(); + + String getLibWhaleName(); boolean isDynamicModulesMode(); + boolean isNoModuleLogEnabled(); + boolean isResourcesHookEnabled(); boolean isBlackWhiteListMode(); diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java b/xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java index 4be8b5f1..0d23657f 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java @@ -1,6 +1,11 @@ package de.robv.android.xposed; import android.os.SELinux; +import android.util.Log; + +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.BinderService; @@ -28,7 +33,36 @@ public final class SELinuxHelper { * @return A boolean indicating whether SELinux is enforcing. */ public static boolean isSELinuxEnforced() { - return sIsSELinuxEnabled && SELinux.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; } /** @@ -56,14 +90,15 @@ public final class SELinuxHelper { // ---------------------------------------------------------------------------- + // TODO: SELinux status private static boolean sIsSELinuxEnabled = false; private static BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly - /*package*/ static void initOnce() { + /*package*/ public static void initOnce() { // ed: we assume all selinux policies have been added lively using magiskpolicy -// try { -// sIsSELinuxEnabled = SELinux.isSELinuxEnabled(); -// } catch (NoClassDefFoundError ignored) {} + try { + sIsSELinuxEnabled = SELinux.isSELinuxEnabled(); + } catch (NoClassDefFoundError ignored) {} } /*package*/ static void initForProcess(String packageName) { diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java index 37b0a583..bde14534 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java @@ -29,6 +29,7 @@ public abstract class XC_MethodReplacement extends XC_MethodHook { Object result = replaceHookedMethod(param); param.setResult(result); } catch (Throwable t) { + XposedBridge.log(t); param.setThrowable(t); } } diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java index 3adb29ab..749809db 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java @@ -24,6 +24,8 @@ import de.robv.android.xposed.services.FileResult; * This class is basically the same as SharedPreferencesImpl from AOSP, but * read-only and without listeners support. Instead, it is made to be * compatible with all ROMs. + * + * @deprecated in Android Pie or later was lost by Google, will not remove */ public final class XSharedPreferences implements SharedPreferences { private static final String TAG = "XSharedPreferences"; @@ -128,11 +130,11 @@ public final class XSharedPreferences implements SharedPreferences { map = mMap; } } catch (XmlPullParserException e) { - Log.w(TAG, "getSharedPreferences", e); + Log.w(TAG, "getSharedPreferences failed for: " + mFilename, e); } catch (FileNotFoundException ignored) { // SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist } catch (IOException e) { - Log.w(TAG, "getSharedPreferences", e); + Log.w(TAG, "getSharedPreferences failed for: " + mFilename, e); } finally { if (result != null && result.stream != null) { try { diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java index f267c78e..dd1a718c 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -143,11 +143,11 @@ public final class XposedBridge { */ public static int getXposedVersion() { // ed: fixed value for now - return 90; + return 91; } /** - * Writes a message to the Xposed error log. + * Writes a message to the Xposed modules log. * *

DON'T FLOOD THE LOG!!! This is only meant for error logging. * If you want to write information/debug messages, use logcat. @@ -155,11 +155,14 @@ public final class XposedBridge { * @param text The log message. */ public synchronized static void log(String text) { + if (EdXpConfigGlobal.getConfig().isNoModuleLogEnabled()) { + return; + } Log.i(TAG, text); } /** - * Logs a stack trace to the Xposed error log. + * Logs a stack trace to the Xposed modules log. * *

DON'T FLOOD THE LOG!!! This is only meant for error logging. * If you want to write information/debug messages, use logcat. diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java index e9a99295..c763fb2e 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java @@ -10,7 +10,6 @@ import android.content.res.XResources; import android.os.Build; import android.os.IBinder; import android.os.Process; -import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -313,7 +312,7 @@ public final class XposedInit { return false; } synchronized (moduleLoadLock) { - final String filename = EdXpConfigGlobal.getConfig().getInstallerBaseDir() + "conf/modules.list"; + final String filename = EdXpConfigGlobal.getConfig().getInstallerConfigPath("modules.list"); BaseService service = SELinuxHelper.getAppDataFileService(); if (!service.checkFileExists(filename)) { Log.e(TAG, "Cannot load any modules because " + filename + " was not found"); @@ -399,14 +398,6 @@ public final class XposedInit { private static boolean loadModule(String apk, ClassLoader topClassLoader, boolean callInitZygote) { Log.i(TAG, "Loading modules from " + apk); - // todo remove this legacy logic - String blackListModulePackageName = EdXpConfigGlobal.getConfig().getBlackListModulePackageName(); - if (!TextUtils.isEmpty(apk) && !TextUtils.isEmpty(blackListModulePackageName) - && apk.contains(blackListModulePackageName)) { - Log.i(TAG, "We are going to take over black list's job..."); - return false; - } - if (!new File(apk).exists()) { Log.e(TAG, " File does not exist"); return false;