diff --git a/app/src/main/assets/module_installer_compat.sh b/app/src/main/assets/module_installer_compat.sh index f62435c..07ef0ab 100644 --- a/app/src/main/assets/module_installer_compat.sh +++ b/app/src/main/assets/module_installer_compat.sh @@ -42,6 +42,8 @@ grep_get_prop() { } fi +# Prevent setenforce because it can causes issues on some devices +setenforce() { true; } # prevent old modules from disabling hidden_apis, please use LSPosed library instead. # See: https://github.com/LSPosed/AndroidHiddenApiBypass settings() { diff --git a/app/src/main/assets/module_installer_wrapper.sh b/app/src/main/assets/module_installer_wrapper.sh new file mode 100644 index 0000000..3963271 --- /dev/null +++ b/app/src/main/assets/module_installer_wrapper.sh @@ -0,0 +1,40 @@ +#!/sbin/sh + +# echo before loading util_functions +ui_print() { echo "$1"; } + +OUTFD=$2 +ZIPFILE=$3 +TMPDIR=/dev/tmp + +# Prevent setenforce because it can causes issues on some devices +setenforce() { true; } +# prevent old modules from disabling hidden_apis, please use LSPosed library instead. +# See: https://github.com/LSPosed/AndroidHiddenApiBypass +settings() { + if [ "$1" == "put" ] && [ "$2" == "global" ] && ([ "$3" == "hidden_api_policy" ] || \ + [ "$3" == "hidden_api_policy_p_apps" ] || [ "$3" == "hidden_api_policy_pre_p_apps" ]); then + true + else + "$(which settings)" "$@" + fi +} + +rm -rf $TMPDIR 2>/dev/null +mkdir -p $TMPDIR +chcon u:object_r:system_file:s0 $TMPDIR || true +cd $TMPDIR + +abort() { + ui_print "$1" + rm -rf $TMPDIR + exit 1 +} + +unzip -o "$ZIPFILE" "META-INF/com/google/android/update-binary" -d $TMPDIR >&2 +[ ! -f "$TMPDIR/META-INF/com/google/android/update-binary" ] && abort "! Unable to extract zip file!" + +. "$TMPDIR/META-INF/com/google/android/update-binary" + +rm -rf $TMPDIR +exit 0 diff --git a/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java index 54156f9..8ad158a 100644 --- a/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java +++ b/app/src/main/java/com/fox2code/mmm/AppUpdateManager.java @@ -29,6 +29,7 @@ public class AppUpdateManager { public static final int FLAG_COMPAT_FORCE_ANSI = 0x0040; public static final int FLAG_COMPAT_FORCE_HIDE = 0x0080; public static final int FLAG_COMPAT_MMT_REBORN = 0x0100; + public static final int FLAG_COMPAT_ZIP_WRAPPER = 0x0200; private static final String TAG = "AppUpdateManager"; private static final AppUpdateManager INSTANCE = new AppUpdateManager(); private static final String RELEASES_API_URL = @@ -217,6 +218,9 @@ public class AppUpdateManager { case "mmtReborn": value |= FLAG_COMPAT_MMT_REBORN; break; + case "wrapper": + value |= FLAG_COMPAT_ZIP_WRAPPER; + break; } } compatDataId.put(line.substring(0, i), value); diff --git a/app/src/main/java/com/fox2code/mmm/NotificationType.java b/app/src/main/java/com/fox2code/mmm/NotificationType.java index 8df26ba..87583fd 100644 --- a/app/src/main/java/com/fox2code/mmm/NotificationType.java +++ b/app/src/main/java/com/fox2code/mmm/NotificationType.java @@ -93,20 +93,11 @@ public enum NotificationType implements NotificationTypeCst { IntentHelper.openFileTo(compatActivity, module, (d, u, s) -> { if (s == IntentHelper.RESPONSE_FILE) { try { - boolean needPatch; - try (ZipFile zipFile = new ZipFile(d)) { - needPatch = zipFile.getEntry("module.prop") == null && - zipFile.getEntry("anykernel.sh") == null; - } - if (needPatch) { + if (needPatch(d)) { Files.patchModuleSimple(Files.read(d), new FileOutputStream(d)); } - try (ZipFile zipFile = new ZipFile(d)) { - needPatch = zipFile.getEntry("module.prop") == null && - zipFile.getEntry("anykernel.sh") == null; - } - if (needPatch) { + if (needPatch(d)) { if (d.exists() && !d.delete()) Log.w(TAG, "Failed to delete non module zip"); Toast.makeText(compatActivity, @@ -141,6 +132,14 @@ public enum NotificationType implements NotificationTypeCst { } }; + private static boolean needPatch(File target) throws IOException { + try (ZipFile zipFile = new ZipFile(target)) { + return zipFile.getEntry("module.prop") == null && + zipFile.getEntry("anykernel.sh") == null && + zipFile.getEntry("META-INF/com/google/android/magisk/module.prop") == null; + } + } + @StringRes public final int textId; @DrawableRes diff --git a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java index a70a99e..6846921 100644 --- a/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java +++ b/app/src/main/java/com/fox2code/mmm/installer/InstallerActivity.java @@ -189,6 +189,7 @@ public class InstallerActivity extends FoxActivity { boolean noPatch = false; boolean isModule = false; boolean isAnyKernel3 = false; + boolean isInstallZipModule = false; errMessage = "File is not a valid zip file"; try (ZipInputStream zipInputStream = new ZipInputStream( new ByteArrayInputStream(rawModule))) { @@ -203,14 +204,21 @@ public class InstallerActivity extends FoxActivity { noPatch = true; isModule = true; break; + } if (entryName.equals("META-INF/com/google/android/magisk/module.prop")) { + noPatch = true; + isInstallZipModule = true; + break; } else if (entryName.endsWith("/tools/ak3-core.sh")) { isAnyKernel3 = true; + } else if (entryName.endsWith( + "/META-INF/com/google/android/magisk/module.prop")) { + isInstallZipModule = true; } else if (entryName.endsWith("/module.prop")) { isModule = true; } } } - if (!isModule && !isAnyKernel3) { + if (!isModule && !isAnyKernel3 && !isInstallZipModule) { if (androidacyBlame) { this.installerTerminal.addLine( "! Note: The following error is probably an Androidacy backend error"); @@ -313,6 +321,7 @@ public class InstallerActivity extends FoxActivity { String moduleId = null; boolean anyKernel3 = false; boolean magiskModule = false; + boolean installZipMagiskModule = false; boolean mmtReborn = false; String MAGISK_PATH = InstallerInitializer.peekMagiskPath(); if (MAGISK_PATH == null) { @@ -338,10 +347,11 @@ public class InstallerActivity extends FoxActivity { bufferedReader.close(); } } - if (zipFile.getEntry( // Check if module hard require 32bit support + if ((zipFile.getEntry( // Check if module hard require 32bit support "common/addon/Volume-Key-Selector/tools/arm64/keycheck") == null && - zipFile.getEntry( - "common/addon/Volume-Key-Selector/install.sh") != null) { + zipFile.getEntry("common/addon/Volume-Key-Selector/install.sh") != null) || + (zipFile.getEntry("META-INF/zbin/keycheck_arm64") == null && + zipFile.getEntry("META-INF/zbin/keycheck_arm") != null)) { needs32bit = true; } ZipEntry moduleProp = zipFile.getEntry("module.prop"); @@ -351,8 +361,11 @@ public class InstallerActivity extends FoxActivity { zipFile.getEntry("setup.sh") != null && magiskModule) { mmtReborn = true; // MMT-Reborn require a separate runtime } - moduleId = PropUtils.readModuleId(zipFile - .getInputStream(zipFile.getEntry("module.prop"))); + if (!magiskModule && (moduleProp = zipFile.getEntry( + "META-INF/com/google/android/magisk/module.prop")) != null) { + installZipMagiskModule = true; + } + moduleId = PropUtils.readModuleId(zipFile.getInputStream(moduleProp)); } catch (IOException ignored) { } int compatFlags = AppUpdateManager.getFlagsForModule(moduleId); @@ -406,6 +419,17 @@ public class InstallerActivity extends FoxActivity { installCommand = "unshare -m " + ASH + " \"" + installExecutable.getAbsolutePath() + "\"" + " 3 1 \"" + file.getAbsolutePath() + "\""; + } else if (installZipMagiskModule || + (compatFlags & AppUpdateManager.FLAG_COMPAT_ZIP_WRAPPER) != 0) { + installExecutable = this.extractInstallScript("module_installer_wrapper.sh"); + if (installExecutable == null) { + this.setInstallStateFinished(false, + "! Failed to extract Magisk module wrapper script", ""); + return; + } + installCommand = ASH + " \"" + + installExecutable.getAbsolutePath() + "\"" + + " 3 1 \"" + file.getAbsolutePath() + "\""; } else if (InstallerInitializer.peekMagiskVersion() >= Constants.MAGISK_VER_CODE_INSTALL_COMMAND && ((compatFlags & AppUpdateManager.FLAG_COMPAT_MAGISK_CMD) != 0 ||