├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── five │ │ └── ec1cff │ │ └── mysysteminjector │ │ └── xposed │ │ ├── Helper.java │ │ └── HookEntry.java │ └── res │ └── values │ ├── array.xml │ └── strings.xml ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── stub ├── .gitignore ├── build.gradle.kts ├── consumer-rules.pro ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java ├── com └── android │ └── internal │ └── app │ ├── ResolverActivityStub.java │ ├── ResolverActivityStubImpl.java │ └── chooser │ └── DisplayResolveInfo.java └── sun └── misc └── Unsafe.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 自用 MIUI 系统 hook 2 | 3 | 支持版本: ~~12.5.7~~ -> 13.0.3 4 | 5 | 作用域:system (系统服务)、android(系统) 6 | 7 | ## 使用方法 8 | 9 | ```sh 10 | mkdir -p /data/system/fuckmiui 11 | touch /data/system/fuckmiui/${feature} 12 | ``` 13 | 14 | feature 为你想要开启的功能(详见下方标题) 15 | 16 | 如果创建了名为 `disable` 的文件,则会关闭所有功能,便于系统无法启动的时候排查问题。 17 | 18 | ## 功能 19 | 20 | 画删除线的是停止维护的功能,不保证可用 21 | 22 | ### nowakepath 23 | 24 | 禁用应用间启动 activity 的警告 25 | 26 | ### ~~installer~~ 27 | 28 | 防止 google installer 被自动卸载 29 | 30 | 如果你想换用 google installer ,需要开启该功能同时卸载 miui installer ,因为系统不允许同时存在两个 installer (会崩)。 31 | 32 | ### nomiuiintent 33 | 34 | 防止 MIUI 锁定 intent (例如调用应用安装器) 35 | 36 | ### ~~protect_mc~~ 37 | 38 | 防止杀进程(不知道什么情况下会触发的自动清理) 39 | 40 | 启用后还需要需要添加文件 `protect_mc_${packageName}` 指定你想要阻止被杀进程的包名。例如 `protect_mc_com.tencent.mobileqq` 。 41 | 42 | 这个功能的历史:作者曾经有一段时间被 MIUI 自动杀 QQ 困扰。按理来说 QQ 应该在各大国产系统的白名单中,也许是云控系统抽风了。 43 | 44 | 由于 QQ 冷启动实在太慢,因此写了这个功能保活。~~没想到用户也有主动帮 QQ 保活的一天。~~ 45 | 46 | ### fonts 47 | 48 | 强制启用 FontManagerService 的更新功能,并禁用基于 fs-verity 的验证。 49 | 50 | 启用后可通过以下命令升级字体: 51 | 52 | ```sh 53 | # /path/to/dummy 是空文件 54 | # 所有路径需要系统服务有读权限,例如 /data/local/tmp 55 | cmd font update /path/to/font.ttf /path/to/dummy 56 | ``` 57 | 58 | 这个功能和 MIUI 无关,理论上适用于任何 Android 12 系统。 59 | 60 | ### xspace 61 | 62 | 1. 在系统服务:允许 shell 指定用户直接启动 activity 而无需弹出选择双开的提示( `am start --user` ) 63 | 2. 在系统:ResolverActivity 直接显示双开 app 的打开方式,无需二次点击。 64 | 3. 修复该版本中点击 xmsf 推送的通知会显示选择双开的 bug 。 65 | 4. 禁止 ResolverActivity 添加 `SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS` flags ,允许悬浮窗在其上显示。 66 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | } 4 | 5 | android { 6 | compileSdk = 35 7 | 8 | defaultConfig { 9 | applicationId = "five.ec1cff.mysysteminjector" 10 | minSdk = 30 11 | targetSdk = 35 12 | versionCode = 1 13 | versionName = "1.0" 14 | } 15 | 16 | buildTypes { 17 | release { 18 | isMinifyEnabled = false 19 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") 20 | } 21 | } 22 | compileOptions { 23 | sourceCompatibility = JavaVersion.VERSION_17 24 | targetCompatibility = JavaVersion.VERSION_17 25 | } 26 | namespace = "five.ec1cff.mysysteminjector" 27 | } 28 | 29 | dependencies { 30 | implementation("androidx.annotation:annotation:1.9.1") 31 | compileOnly("de.robv.android.xposed:api:82") 32 | compileOnly(project(":stub")) 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | five.ec1cff.mysysteminjector.xposed.HookEntry -------------------------------------------------------------------------------- /app/src/main/java/five/ec1cff/mysysteminjector/xposed/Helper.java: -------------------------------------------------------------------------------- 1 | package five.ec1cff.mysysteminjector.xposed; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | import androidx.annotation.Nullable; 6 | 7 | import java.lang.invoke.MethodHandle; 8 | import java.lang.invoke.MethodHandleInfo; 9 | import java.lang.invoke.MethodHandles; 10 | import java.lang.reflect.Constructor; 11 | import java.lang.reflect.Executable; 12 | import java.lang.reflect.InvocationTargetException; 13 | import java.lang.reflect.Member; 14 | import java.lang.reflect.Method; 15 | import java.lang.reflect.Modifier; 16 | 17 | import de.robv.android.xposed.XposedBridge; 18 | import sun.misc.Unsafe; 19 | 20 | // https://github.com/LSPosed/AndroidHiddenApiBypass/blob/2e46e453c83035d201a90cc05cfd2a7aa0922fa7/library/src/main/java/org/lsposed/hiddenapibypass/HiddenApiBypass.java#L206 21 | @SuppressLint({"SoonBlockedPrivateApi", "DiscouragedPrivateApi"}) 22 | public class Helper { 23 | private final static Method deoptimizeMethod; 24 | 25 | static { 26 | Method m = null; 27 | try { 28 | m = XposedBridge.class.getDeclaredMethod("deoptimizeMethod", Member.class); 29 | } catch (Throwable t) { 30 | XposedBridge.log("cannot get deoptimizeMethod"); 31 | } 32 | deoptimizeMethod = m; 33 | } 34 | 35 | static void deoptimizeMethod(Class c, String n) throws InvocationTargetException, IllegalAccessException { 36 | for (Method m : c.getDeclaredMethods()) { 37 | if (deoptimizeMethod != null && m.getName().equals(n)) { 38 | deoptimizeMethod.invoke(null, m); 39 | } 40 | } 41 | } 42 | 43 | private static final Unsafe unsafe; 44 | private static final long methodsOffset; 45 | private static final long artMethodSize; 46 | private static final long artMethodBias; 47 | private static final long artOffset; 48 | private static final long infoOffset; 49 | private static final long memberOffset; 50 | 51 | private static class NeverCall { 52 | private static void a() { 53 | } 54 | 55 | private static void b() { 56 | } 57 | } 58 | 59 | static { 60 | try { 61 | unsafe = (Unsafe) Unsafe.class.getDeclaredMethod("getUnsafe").invoke(null); 62 | assert unsafe != null; 63 | artOffset = unsafe.objectFieldOffset(MethodHandle.class.getDeclaredField("artFieldOrMethod")); 64 | infoOffset = unsafe.objectFieldOffset(Class.forName("java.lang.invoke.MethodHandleImpl").getDeclaredField("info")); 65 | methodsOffset = unsafe.objectFieldOffset(Class.class.getDeclaredField("methods")); 66 | memberOffset = unsafe.objectFieldOffset(Class.forName("java.lang.invoke.MethodHandleImpl$HandleInfo").getDeclaredField("member")); 67 | Method mA = Helper.NeverCall.class.getDeclaredMethod("a"); 68 | Method mB = Helper.NeverCall.class.getDeclaredMethod("b"); 69 | mA.setAccessible(true); 70 | mB.setAccessible(true); 71 | MethodHandle mhA = MethodHandles.lookup().unreflect(mA); 72 | MethodHandle mhB = MethodHandles.lookup().unreflect(mB); 73 | long aAddr = unsafe.getLong(mhA, artOffset); 74 | long bAddr = unsafe.getLong(mhB, artOffset); 75 | long aMethods = unsafe.getLong(Helper.NeverCall.class, methodsOffset); 76 | artMethodSize = bAddr - aAddr; 77 | artMethodBias = aAddr - aMethods - artMethodSize; 78 | } catch (Throwable t) { 79 | XposedBridge.log("failed to initialize helper"); 80 | throw new ExceptionInInitializerError(t); 81 | } 82 | } 83 | 84 | @Nullable 85 | public static Constructor getClInit(Class clazz) { 86 | if (clazz.isPrimitive() || clazz.isArray()) return null; 87 | MethodHandle mh; 88 | try { 89 | Method mA = Helper.NeverCall.class.getDeclaredMethod("a"); 90 | mA.setAccessible(true); 91 | mh = MethodHandles.lookup().unreflect(mA); 92 | } catch (NoSuchMethodException | IllegalAccessException e) { 93 | return null; 94 | } 95 | long methods = unsafe.getLong(clazz, methodsOffset); 96 | if (methods == 0) return null; 97 | int numMethods = unsafe.getInt(methods); 98 | for (int i = 0; i < numMethods; i++) { 99 | long method = methods + i * artMethodSize + artMethodBias; 100 | unsafe.putLong(mh, artOffset, method); 101 | unsafe.putObject(mh, infoOffset, null); 102 | try { 103 | MethodHandles.lookup().revealDirect(mh); 104 | } catch (Throwable ignored) { 105 | } 106 | MethodHandleInfo info = (MethodHandleInfo) unsafe.getObject(mh, infoOffset); 107 | Executable member = (Executable) unsafe.getObject(info, memberOffset); 108 | if (member instanceof Constructor && (member.getModifiers() & Modifier.STATIC) != 0) return (Constructor) member; 109 | } 110 | return null; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/five/ec1cff/mysysteminjector/xposed/HookEntry.java: -------------------------------------------------------------------------------- 1 | package five.ec1cff.mysysteminjector.xposed; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.ApplicationInfo; 7 | import android.content.pm.ResolveInfo; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.UserHandle; 10 | import android.view.View; 11 | import android.view.Window; 12 | 13 | import java.io.File; 14 | import java.util.List; 15 | import java.util.Objects; 16 | 17 | import de.robv.android.xposed.IXposedHookLoadPackage; 18 | import de.robv.android.xposed.XC_MethodHook; 19 | import de.robv.android.xposed.XC_MethodReplacement; 20 | import de.robv.android.xposed.XposedBridge; 21 | import de.robv.android.xposed.XposedHelpers; 22 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 23 | 24 | @SuppressWarnings("unchecked") 25 | public class HookEntry implements IXposedHookLoadPackage { 26 | private static final String TAG = "MySystemInjector"; 27 | private static final String WORKDIR = "/data/system/fuckmiui"; 28 | boolean loaded = false; 29 | public static boolean isFeatureEnabled(String featureName) { 30 | return new File(new File(WORKDIR), featureName).exists(); 31 | } 32 | 33 | public static void log(String msg) { 34 | XposedBridge.log("[" + TAG + "] " + msg); 35 | } 36 | 37 | public static void log(String msg, Throwable t) { 38 | XposedBridge.log("[" + TAG + "] " + msg); 39 | XposedBridge.log(t); 40 | } 41 | 42 | @Override 43 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 44 | boolean inSystemServer = lpparam.packageName.equals("android") && lpparam.processName.equals("android"); 45 | boolean inSystem = lpparam.packageName.equals("system"); 46 | XposedBridge.log("handleLoadPackage inSystem=" + inSystem + " package=" + lpparam.packageName + " process=" + lpparam.processName); 47 | if (isFeatureEnabled("share") && !inSystem) { 48 | hookShareInUI(lpparam); 49 | } 50 | if (!inSystemServer && !inSystem) { 51 | return; 52 | } 53 | if (loaded) return; 54 | loaded = true; 55 | 56 | if (isFeatureEnabled("disable")) { 57 | log("disabled, exit"); 58 | return; 59 | } 60 | 61 | if (inSystem) { 62 | if (isFeatureEnabled("xspace")) { 63 | hookXSpaceInUI(lpparam); 64 | } 65 | } 66 | 67 | if (!inSystemServer) return; 68 | 69 | try { 70 | if (isFeatureEnabled("nowakepath")) { 71 | log("hook for nowakepath"); 72 | XposedBridge.hookAllMethods( 73 | XposedHelpers.findClass("miui.app.ActivitySecurityHelper", lpparam.classLoader), 74 | "getCheckStartActivityIntent", 75 | XC_MethodReplacement.DO_NOTHING 76 | ); 77 | // miui-framework.jar 78 | XposedBridge.hookAllMethods( 79 | XposedHelpers.findClass("miui.security.SecurityManager", lpparam.classLoader), 80 | "getCheckStartActivityIntent", 81 | XC_MethodReplacement.DO_NOTHING 82 | ); 83 | log("hook done"); 84 | } 85 | } catch (Throwable t) { 86 | XposedBridge.log(t); 87 | } 88 | 89 | try { 90 | if (isFeatureEnabled("installer")) { 91 | log("hook for installer"); 92 | XposedBridge.hookAllMethods( 93 | XposedHelpers.findClass("com.android.server.pm.PackageManagerServiceInjector", lpparam.classLoader), 94 | "checkPackageInstallerStatus", 95 | new XC_MethodHook() { 96 | @Override 97 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 98 | XposedBridge.log(TAG + "tried to protect installer"); 99 | Object curPkgSettings = param.args[1]; 100 | Object mPackages = XposedHelpers.getObjectField(curPkgSettings, "mPackages"); 101 | Object googleInstaller = XposedHelpers.callMethod(mPackages, "get", "com.google.android.packageinstaller"); 102 | Object miuiInstaller = XposedHelpers.callMethod(mPackages, "get", "com.miui.packageinstaller"); 103 | if (googleInstaller == null || miuiInstaller == null) { 104 | log("failed to find PackageSetting, cancel"); 105 | return; 106 | } 107 | log("google=" + googleInstaller); 108 | log("miui=" + miuiInstaller); 109 | XposedHelpers.callMethod(googleInstaller, "setInstalled", true, 0); 110 | XposedHelpers.callMethod(miuiInstaller, "setInstalled", false, 0); 111 | try { 112 | Object installer = XposedHelpers.callMethod(param.args[0], "getRequiredInstallerLPr"); 113 | log("replace installer:" + installer); 114 | } catch (RuntimeException e) { 115 | // ? 116 | log("failed to replace installer, call original method fallback...", e); 117 | return; 118 | } catch (Throwable t) { 119 | log("something wrong", t); 120 | } 121 | param.setResult(null); 122 | } 123 | } 124 | ); 125 | log("hook done"); 126 | } 127 | } catch (Throwable t) { 128 | log("hook installer", t); 129 | } 130 | 131 | try { 132 | if (isFeatureEnabled("nomiuiintent")) { 133 | log("hook for nomiuiintent"); 134 | // for hyperos 1.0.2.0 135 | 136 | XposedHelpers.findAndHookMethod("com.android.server.pm.PackageManagerServiceImpl", lpparam.classLoader, 137 | "hookChooseBestActivity", 138 | Intent.class, String.class, long.class, List.class, int.class, ResolveInfo.class, new XC_MethodHook() { 139 | @Override 140 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 141 | param.setResult(param.args[5]); // defaultValue 142 | } 143 | } 144 | ); 145 | /* 146 | // for 13.0.3 147 | // miui-services.jar 148 | XposedHelpers.findAndHookMethod("com.android.server.pm.PackageManagerServiceImpl", lpparam.classLoader, 149 | "hookChooseBestActivity", 150 | Intent.class, String.class, int.class, List.class, int.class, ResolveInfo.class, new XC_MethodHook() { 151 | @Override 152 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 153 | param.setResult(param.args[5]); // defaultValue 154 | } 155 | } 156 | );*/ 157 | // for 12.5.7 158 | // services.jar 159 | /* 160 | XposedBridge.hookAllMethods( 161 | XposedHelpers.findClass("com.android.server.pm.PackageManagerServiceInjector", lpparam.classLoader), 162 | "checkMiuiIntent", 163 | new XC_MethodHook() { 164 | @Override 165 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 166 | param.setResult( 167 | XposedHelpers.getObjectField(param.args[0], "mResolveInfo") 168 | ); 169 | } 170 | } 171 | );*/ 172 | log("nomiuiintent hook done"); 173 | } 174 | } catch (Throwable t) { 175 | log("nomiuiintent error", t); 176 | } 177 | 178 | try { 179 | if (isFeatureEnabled("protect_mc")) { 180 | log("hook for ProcessMemoryCleaner"); 181 | XposedHelpers.findAndHookMethod( 182 | XposedHelpers.findClass("com.android.server.am.ProcessMemoryCleaner", lpparam.classLoader), 183 | "checkBackgroundApp", 184 | String.class, int.class, 185 | new XC_MethodHook() { 186 | @Override 187 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 188 | var packageName = (String) param.args[0]; 189 | if (isFeatureEnabled("protect_mc_" + packageName)) { 190 | // XposedBridge.log("protect " + packageName + " from PMC"); 191 | param.setResult(null); 192 | } 193 | } 194 | } 195 | ); 196 | } 197 | } catch (Throwable t) { 198 | log("protect_mc error", t); 199 | } 200 | 201 | try { 202 | if (isFeatureEnabled("fonts")) { 203 | log("hook for fonts"); 204 | ThreadLocal isCreating = new ThreadLocal<>(); 205 | Class FMS = XposedHelpers.findClass("com.android.server.graphics.fonts.FontManagerService", lpparam.classLoader); 206 | Class FUI = XposedHelpers.findClass("com.android.server.graphics.fonts.FontManagerService$FsverityUtilImpl", lpparam.classLoader); 207 | XposedBridge.hookAllConstructors( 208 | FMS, 209 | new XC_MethodHook() { 210 | @Override 211 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 212 | isCreating.set(true); 213 | } 214 | 215 | @Override 216 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 217 | isCreating.set(false); 218 | } 219 | } 220 | ); 221 | XposedBridge.hookAllMethods( 222 | XposedHelpers.findClass("com.android.internal.security.VerityUtils", lpparam.classLoader), 223 | "isFsVeritySupported", 224 | new XC_MethodHook() { 225 | @Override 226 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 227 | if (isCreating.get()) { 228 | param.setResult(true); 229 | isCreating.set(false); 230 | } 231 | } 232 | } 233 | ); 234 | XposedBridge.hookAllMethods( 235 | FUI, 236 | "hasFsverity", 237 | new XC_MethodHook() { 238 | @Override 239 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 240 | param.setResult(true); 241 | } 242 | } 243 | ); 244 | XposedBridge.hookAllMethods( 245 | FUI, 246 | "setUpFsverity", 247 | new XC_MethodReplacement() { 248 | @Override 249 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 250 | return null; 251 | } 252 | } 253 | ); 254 | } 255 | } catch (Throwable t) { 256 | XposedBridge.log(t); 257 | } 258 | 259 | try { 260 | if (isFeatureEnabled("clipboard")) { 261 | XposedBridge.hookAllMethods( 262 | XposedHelpers.findClass("com.android.server.clipboard.ClipboardService", lpparam.classLoader), 263 | "clipboardAccessAllowed", 264 | new XC_MethodHook() { 265 | @Override 266 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 267 | var pkg = (String) param.args[1]; 268 | if (pkg == null) return; 269 | if ("com.fooview.android.fooview".equals(pkg) || "com.termux".equals(pkg) || "com.termux.api".equals(pkg)) 270 | param.setResult(true); 271 | } 272 | } 273 | ); 274 | } 275 | } catch (Throwable t) { 276 | XposedBridge.log(t); 277 | } 278 | 279 | try { 280 | if (isFeatureEnabled("fixsync")) { 281 | // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/wm/WindowState.java;l=5756;drc=4eb30271c338af7ee6abcbd2b7a9a0721db0595b 282 | // some goned accessibility windows does not get synced 283 | XposedBridge.hookAllMethods( 284 | XposedHelpers.findClass("com.android.server.wm.WindowState", lpparam.classLoader), 285 | "isSyncFinished", 286 | new XC_MethodHook() { 287 | @Override 288 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 289 | if ((int) XposedHelpers.getObjectField(param.thisObject, "mViewVisibility") != View.VISIBLE 290 | && XposedHelpers.getObjectField(param.thisObject, "mActivityRecord") == null) { 291 | // XposedBridge.log("no wait on " + param.thisObject); 292 | param.setResult(true); 293 | } 294 | } 295 | } 296 | ); 297 | } 298 | } catch (Throwable t) { 299 | XposedBridge.log("fixsync"); 300 | XposedBridge.log(t); 301 | } 302 | 303 | hookXSpace(lpparam); 304 | } 305 | 306 | private void hookShareInUI(XC_LoadPackage.LoadPackageParam lpparam) { 307 | try { 308 | /* 309 | var impl = new ResolverActivityStubImpl() { 310 | @Override 311 | public boolean useAospShareSheet() { 312 | XposedBridge.log("useAospShareSheet"); 313 | return true; 314 | } 315 | }; 316 | XposedHelpers.callStaticMethod( 317 | XposedHelpers.findClass("com.miui.base.MiuiStubRegistry", lpparam.classLoader), 318 | "registerSingleton", impl 319 | ); 320 | XposedHelpers.setStaticObjectField(ResolverActivityStub.class, "sInstance", impl); 321 | */ 322 | XposedBridge.hookAllMethods( 323 | XposedHelpers.findClass("com.android.internal.app.ResolverActivityStubImpl", lpparam.classLoader), 324 | "useAospShareSheet", 325 | new XC_MethodHook() { 326 | @Override 327 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 328 | XposedBridge.log("useAospShareSheet"); 329 | param.setResult(true); 330 | } 331 | } 332 | ); 333 | XposedBridge.log("hook installed"); 334 | } catch (Throwable t) { 335 | XposedBridge.log(t); 336 | } 337 | } 338 | 339 | @SuppressWarnings("unchecked") 340 | private void hookXSpace(XC_LoadPackage.LoadPackageParam lpparam) { 341 | if (!isFeatureEnabled("xspace")) return; 342 | log("[MySystemInjector] hook for xspace"); 343 | try { 344 | Class classXSpaceManager = XposedHelpers.findClass("com.miui.server.xspace.XSpaceManagerServiceImpl", lpparam.classLoader); 345 | List list = (List) XposedHelpers.getStaticObjectField(classXSpaceManager, "sCrossUserCallingPackagesWhiteList"); 346 | if (list != null) { 347 | list.add("com.android.shell"); 348 | list.add("com.xiaomi.xmsf"); 349 | log("add required packages to whitelist at init"); 350 | } else { 351 | log("whitelist is null"); 352 | } 353 | List publicActions = (List) XposedHelpers.getStaticObjectField(classXSpaceManager, "sPublicActionList"); 354 | if (publicActions != null) { 355 | publicActions.clear(); 356 | log("clear publicActionList"); 357 | } else { 358 | log("publicActionList is null"); 359 | } 360 | } catch (Throwable t) { 361 | log("hook xspace shell failed", t); 362 | } 363 | } 364 | 365 | private void hookXSpaceInUI(XC_LoadPackage.LoadPackageParam lpparam) { 366 | log("hookForXspace in system"); 367 | XposedBridge.hookAllMethods( 368 | XposedHelpers.findClass("com.android.internal.app.ResolverListController", lpparam.classLoader), 369 | "getResolversForIntent", 370 | new XC_MethodHook() { 371 | @Override 372 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 373 | List result = (List) param.getResult(); 374 | List intents = (List) param.args[2]; 375 | if (intents != null && !intents.isEmpty()) { 376 | String action = intents.get(0).getAction(); 377 | if ("miui.intent.action.MIUI_CHOOSER".equals(action) 378 | || Intent.ACTION_CHOOSER.equals(action)) { 379 | return; 380 | } 381 | } 382 | if (result == null) return; 383 | List/*com.android.internal.app.ResolverActivity$ResolvedComponentInfo*/ listForXSpace = (List) XposedHelpers.callMethod(param.thisObject, "getResolversForIntentAsUser", 384 | param.args[0], param.args[1], param.args[2], 385 | XposedHelpers.callStaticMethod(android.os.UserHandle.class, "of", 999 386 | ) 387 | ); 388 | for (Object infoXs : listForXSpace) { 389 | List rInfosXs = (List) XposedHelpers.getObjectField(infoXs, "mResolveInfos"); 390 | if (rInfosXs.isEmpty()) continue; 391 | ResolveInfo rInfoXs = rInfosXs.get(0); 392 | rInfosXs.set(0, new MyResolveInfo(rInfoXs)); 393 | for (Object orig : result) { 394 | List infos = (List) XposedHelpers.getObjectField(orig, "mResolveInfos"); 395 | if (infos.isEmpty()) continue; 396 | ResolveInfo oldInfo = infos.get(0); 397 | if (Objects.equals(oldInfo.activityInfo.packageName, rInfoXs.activityInfo.packageName) 398 | && Objects.equals(oldInfo.activityInfo.name, rInfoXs.activityInfo.name)) { 399 | infos.set(0, new MyResolveInfo(oldInfo)); 400 | } 401 | } 402 | } 403 | log("add resolveInfo " + result.size() + " + " + listForXSpace.size()); 404 | result.addAll(listForXSpace); 405 | } 406 | } 407 | ); 408 | 409 | XposedBridge.hookAllMethods( 410 | XposedHelpers.findClass("com.android.internal.app.ResolverListAdapter", lpparam.classLoader), 411 | "shouldAddResolveInfo", 412 | new XC_MethodHook() { 413 | @Override 414 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 415 | Object o = param.args[0]; 416 | ResolveInfo resolve = (ResolveInfo) XposedHelpers.getObjectField(o, "mResolveInfo"); 417 | log("check resolveinfo " + resolve); 418 | if (resolve.activityInfo.applicationInfo.uid / 100000 == 999) { 419 | log("allow resolveinfo " + resolve); 420 | param.setResult(true); 421 | } 422 | } 423 | } 424 | ); 425 | 426 | XposedBridge.hookAllMethods( 427 | XposedHelpers.findClass("com.android.internal.app.ResolverListAdapter$TargetPresentationGetter", lpparam.classLoader), 428 | "getIconBitmap", 429 | new XC_MethodHook() { 430 | @Override 431 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 432 | log("get icon"); 433 | ApplicationInfo ai = (ApplicationInfo) XposedHelpers.getObjectField(param.thisObject, "mAi"); 434 | if (ai.uid / 100000 == 999) { 435 | param.args[0] = XposedHelpers.callStaticMethod(UserHandle.class, "of", 999); 436 | } 437 | } 438 | } 439 | ); 440 | 441 | ThreadLocal currentResolveInfo = new ThreadLocal<>(); 442 | 443 | Class classMIUIResolverActivity = XposedHelpers.findClass("com.android.internal.app.MiuiResolverActivity", lpparam.classLoader); 444 | 445 | XposedBridge.hookAllMethods( 446 | classMIUIResolverActivity, 447 | "safelyStartActivity", new XC_MethodHook() { 448 | @Override 449 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 450 | ResolveInfo ri = (ResolveInfo) XposedHelpers.getObjectField(param.args[0], "mResolveInfo"); 451 | log("startActivity ri=" + ri + " class=" + ri.getClass()); 452 | if (ri instanceof MyResolveInfo) { 453 | currentResolveInfo.set((MyResolveInfo) ri); 454 | } 455 | } 456 | 457 | @Override 458 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 459 | currentResolveInfo.remove(); 460 | } 461 | }); 462 | 463 | XposedBridge.hookAllMethods( 464 | classMIUIResolverActivity, 465 | "startAsCaller", 466 | new XC_MethodHook() { 467 | @Override 468 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 469 | log("starting"); 470 | MyResolveInfo current = currentResolveInfo.get(); 471 | if (current != null) { 472 | Intent intent = (Intent) param.args[0]; 473 | // see com.miui.server.xspace.XSpaceManagerServiceImpl#checkXSpaceControl 474 | intent.putExtra("android.intent.extra.xspace_userid_selected", true); 475 | int userId = current.activityInfo.applicationInfo.uid / 100000; 476 | log("set to " + userId); 477 | param.args[1] = userId; 478 | } 479 | } 480 | } 481 | ); 482 | 483 | XposedBridge.hookAllMethods( 484 | XposedHelpers.findClass("com.android.internal.app.ResolverActivityStubImpl$LoadIconTask", lpparam.classLoader), 485 | "doInBackground", 486 | new XC_MethodHook() { 487 | @Override 488 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 489 | ResolveInfo info = (ResolveInfo) XposedHelpers.getObjectField(param.thisObject, "mResolveInfo"); 490 | if (info.activityInfo.applicationInfo.uid / 100000 != 999) return; 491 | log("fixup icon"); 492 | Drawable result = (Drawable) param.getResult(); 493 | Context context = (Context) XposedHelpers.getObjectField(XposedHelpers.getObjectField(param.thisObject, "this$0"), "mContext"); 494 | Drawable realResult = context.getPackageManager().getUserBadgedIcon(result, (UserHandle) XposedHelpers.callStaticMethod(UserHandle.class, "of", 999)); 495 | param.setResult(realResult); 496 | } 497 | } 498 | ); 499 | 500 | try { 501 | Helper.deoptimizeMethod(classMIUIResolverActivity, "onStart"); 502 | } catch (Throwable t) { 503 | log("failed to deoptimize", t); 504 | } 505 | 506 | XposedBridge.hookAllMethods(Window.class, "addSystemFlags", 507 | new XC_MethodHook() { 508 | @Override 509 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 510 | log("clear hide non system overlay windows flags"); 511 | param.args[0] = (int) param.args[0] & ~524288 /*SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS*/; 512 | } 513 | }); 514 | 515 | XposedBridge.hookAllMethods(classMIUIResolverActivity, "showTargetDetails", 516 | new XC_MethodHook() { 517 | @Override 518 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 519 | ResolveInfo ri = (ResolveInfo) param.args[0]; 520 | Activity activity = (Activity) param.thisObject; 521 | if (ri.activityInfo.applicationInfo.uid / 100000 == 999) { 522 | Intent intent = new Intent().setAction("miui.intent.action.APP_MANAGER_APPLICATION_DETAIL") 523 | .putExtra("package_name", ri.activityInfo.packageName) 524 | .putExtra("miui.intent.extra.USER_ID", 999); 525 | activity.startActivity(intent); 526 | XposedHelpers.callMethod(activity, "dismiss"); 527 | param.setResult(null); 528 | } 529 | } 530 | }); 531 | } 532 | 533 | private static class MyResolveInfo extends ResolveInfo { 534 | MyResolveInfo(ResolveInfo info) { 535 | super(info); 536 | } 537 | } 538 | } 539 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | android 5 | system 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MySystemInjector 3 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | plugins { 3 | id("com.android.application") version "8.8.0" apply false 4 | id("com.android.library") version "8.8.0" apply false 5 | } 6 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | android.defaults.buildfeatures.buildconfig=true 21 | android.nonTransitiveRClass=false 22 | android.nonFinalResIds=false -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5ec1cff/MySystemInjector/cafa8d0e5ff659c5b6b5588fdf192589d1b01f0e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Feb 24 21:36:41 CST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | google() 12 | mavenCentral() 13 | maven { setUrl("https://api.xposed.info/") } 14 | } 15 | } 16 | 17 | rootProject.name = "MySystemInjector" 18 | include(":app") 19 | include(":stub") 20 | -------------------------------------------------------------------------------- /stub/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /stub/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | } 4 | 5 | android { 6 | namespace = "io.github.a13e300.tools.stub" 7 | compileSdk = 35 8 | 9 | defaultConfig { 10 | minSdk = 27 11 | consumerProguardFiles("consumer-rules.pro") 12 | } 13 | 14 | buildTypes { 15 | release { 16 | isMinifyEnabled = false 17 | proguardFiles( 18 | getDefaultProguardFile("proguard-android-optimize.txt"), 19 | "proguard-rules.pro" 20 | ) 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility = JavaVersion.VERSION_17 25 | targetCompatibility = JavaVersion.VERSION_17 26 | } 27 | } 28 | 29 | dependencies { 30 | 31 | } -------------------------------------------------------------------------------- /stub/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/5ec1cff/MySystemInjector/cafa8d0e5ff659c5b6b5588fdf192589d1b01f0e/stub/consumer-rules.pro -------------------------------------------------------------------------------- /stub/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /stub/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /stub/src/main/java/com/android/internal/app/ResolverActivityStub.java: -------------------------------------------------------------------------------- 1 | package com.android.internal.app; 2 | 3 | public class ResolverActivityStub { 4 | } 5 | -------------------------------------------------------------------------------- /stub/src/main/java/com/android/internal/app/ResolverActivityStubImpl.java: -------------------------------------------------------------------------------- 1 | package com.android.internal.app; 2 | 3 | public class ResolverActivityStubImpl extends ResolverActivityStub { 4 | public boolean useAospShareSheet() { 5 | throw new IllegalArgumentException("Stub!"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /stub/src/main/java/com/android/internal/app/chooser/DisplayResolveInfo.java: -------------------------------------------------------------------------------- 1 | package com.android.internal.app.chooser; 2 | 3 | public class DisplayResolveInfo { 4 | } 5 | -------------------------------------------------------------------------------- /stub/src/main/java/sun/misc/Unsafe.java: -------------------------------------------------------------------------------- 1 | package sun.misc; 2 | 3 | public class Unsafe { 4 | public static Unsafe getUnsafe() { 5 | throw new RuntimeException(""); 6 | } 7 | public native long getLong(Object obj, long offset); 8 | public native void putLong(Object obj, long offset, long newValue); 9 | public native Object getObject(Object obj, long offset); 10 | public native void putObject(Object obj, long offset, Object newValue); 11 | public native int getInt(long address); 12 | public long objectFieldOffset(java.lang.reflect.Field field) { 13 | throw new RuntimeException("Stub!"); 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------