diff --git a/app/build.gradle b/app/build.gradle index 816286f46..4afd2fd90 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,6 +62,7 @@ dependencies { implementation 'com.atlassian.commonmark:commonmark:0.9.0' implementation 'org.bouncycastle:bcprov-jdk15on:1.57' implementation 'org.bouncycastle:bcpkix-jdk15on:1.57' + implementation 'org.kamranzafar:jtar:2.3' implementation 'com.google.android.gms:play-services-safetynet:9.0.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java index 2a539c254..1026be26c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -100,6 +100,7 @@ public class MagiskManager extends Application { public int suNamespaceMode; public String localeConfig; public int updateChannel; + public String bootFormat; // Global resources public SharedPreferences prefs; @@ -176,6 +177,7 @@ public class MagiskManager extends Application { updateNotification = prefs.getBoolean("notification", true); updateChannel = Utils.getPrefsInt(prefs, "update_channel", CheckUpdates.STABLE_CHANNEL); + bootFormat = prefs.getString("boot_format", ".img"); } public void toast(String msg, int duration) { @@ -225,6 +227,7 @@ public class MagiskManager extends Application { .putString("mnt_ns", String.valueOf(suNamespaceMode)) .putString("update_channel", String.valueOf(updateChannel)) .putString("locale", localeConfig) + .putString("boot_format", bootFormat) .apply(); // Create notification channel on Android O diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java index dea0b4ac7..994620274 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java @@ -8,10 +8,16 @@ import android.text.TextUtils; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.AdaptiveList; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.TarEntry; import com.topjohnwu.magisk.utils.ZipUtils; +import org.kamranzafar.jtar.TarOutputStream; + import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -135,7 +141,7 @@ public class InstallMagisk extends ParallelTask { getShell().sh(mList, "cd " + install, "KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " + - "update-binary indep boot_patch.sh " + boot + " 2>&1" + + "update-binary indep boot_patch.sh " + boot + " && echo 'Success!' || echo 'Failed!'" ); @@ -146,10 +152,36 @@ public class InstallMagisk extends ParallelTask { mList.add(""); switch (mode) { case PATCH_MODE: - // Move boot image - File dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + "patched_boot.img"); + File dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/patched_boot" + mm.bootFormat); dest.getParentFile().mkdirs(); - getShell().sh_raw("cp " + patched_boot + " " + dest); + switch (mm.bootFormat) { + case ".img": + getShell().sh_raw("cp -f " + patched_boot + " " + dest); + break; + case ".img.tar": + // Workaround root shell issues so we can access the file through Java + if (Shell.rootAccess()) { + // Get non-root UID + int uid = mm.getApplicationInfo().uid; + // Get app selabel + String selabel = getShell().su("/system/bin/ls -dZ " + install + " | cut -d' ' -f1").get(0); + getShell().su( + "chcon " + selabel + " " + patched_boot, + "chown " + uid + "." + uid + " " + patched_boot); + } + TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest))); + tar.putNextEntry(new TarEntry(patched_boot, "boot.img")); + byte buffer[] = new byte[4096]; + BufferedInputStream in = new BufferedInputStream(new FileInputStream(patched_boot)); + int len; + while ((len = in.read(buffer)) != -1) { + tar.write(buffer, 0, len); + } + tar.flush(); + tar.close(); + in.close(); + break; + } mList.add("*********************************"); mList.add(" Patched Boot Image is placed in "); mList.add(" " + dest + " "); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/TarEntry.java b/app/src/main/java/com/topjohnwu/magisk/utils/TarEntry.java new file mode 100644 index 000000000..88a7f60bf --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/TarEntry.java @@ -0,0 +1,27 @@ +package com.topjohnwu.magisk.utils; + +import org.kamranzafar.jtar.TarHeader; + +import java.io.File; + +public class TarEntry extends org.kamranzafar.jtar.TarEntry { + + public TarEntry(File file, String entryName) { + super(file, entryName); + } + + public TarEntry(byte[] headerBuf) { + super(headerBuf); + } + + /* + * Workaround missing java.nio.file.attribute.PosixFilePermission + * Simply just assign a default permission to the file + * */ + + @Override + public void extractTarHeader(String entryName) { + int permissions = file.isDirectory() ? 040755 : 0100644; + header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions); + } +} diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 9742781fb..cec6cd796 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -77,4 +77,9 @@ @string/settings_update_beta + + .img + .img.tar + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cd3544bf1..8bd4947d4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -156,9 +156,12 @@ Temporarily hide Magisk Manager.\nThis will install a new app called \"Unhide Magisk Manager\" Language (System Default) + Update Settings Update Channel Stable Beta + Patched Boot Output File Format + Select the output file format of the patched boot image\nChoose .img to flash through fastboot/download mode\nChoose .img.tar to flash with ODIN Magisk Core Only Mode Enable only core features, all modules will not be loaded. MagiskSU, MagiskHide, and systemless hosts will still be enabled diff --git a/app/src/main/res/xml/app_settings.xml b/app/src/main/res/xml/app_settings.xml index ffa838e18..0224e6aea 100644 --- a/app/src/main/res/xml/app_settings.xml +++ b/app/src/main/res/xml/app_settings.xml @@ -10,6 +10,22 @@ android:title="@string/settings_dark_theme_title" android:summary="@string/settings_dark_theme_summary" /> + + + + + + + + - - - +