From db8fd2c913f38204f4048f0d279cefa31d663a56 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 31 Aug 2017 03:07:33 +0800 Subject: [PATCH] Add boot image file patch --- .../com/topjohnwu/magisk/FlashActivity.java | 51 ++++-- .../com/topjohnwu/magisk/MagiskFragment.java | 146 ++++++++++++------ .../com/topjohnwu/magisk/ModulesFragment.java | 2 +- .../topjohnwu/magisk/SettingsActivity.java | 1 + .../com/topjohnwu/magisk/asyncs/FlashZip.java | 14 +- .../magisk/asyncs/PatchBootImage.java | 145 +++++++++++++++++ .../magisk/asyncs/ProcessRepoZip.java | 5 +- .../com/topjohnwu/magisk/utils/ZipUtils.java | 42 ++--- app/src/main/res/values/strings.xml | 4 + 9 files changed, 325 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/asyncs/PatchBootImage.java diff --git a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java index 9fbcc00e9..db45b1237 100644 --- a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk; +import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.ActionBar; @@ -8,12 +9,17 @@ import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import com.topjohnwu.magisk.asyncs.FlashZip; +import com.topjohnwu.magisk.asyncs.PatchBootImage; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.utils.AdaptiveList; +import com.topjohnwu.magisk.utils.Shell; + +import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; @@ -21,11 +27,15 @@ import butterknife.OnClick; public class FlashActivity extends Activity { + public static final String SET_ACTION = "action"; + public static final String SET_BOOT_URI = "boot_uri"; + public static final String FLASH_ZIP = "flash"; + public static final String PATCH_BOOT = "patch"; + @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.flash_logs) RecyclerView flashLogs; @BindView(R.id.button_panel) LinearLayout buttonPanel; - - private AdaptiveList rootShellOutput; + @BindView(R.id.reboot) Button reboot; @OnClick(R.id.no_thanks) public void dismiss() { @@ -42,22 +52,33 @@ public class FlashActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flash); ButterKnife.bind(this); - rootShellOutput = new AdaptiveList<>(flashLogs); + AdaptiveList rootShellOutput = new AdaptiveList<>(flashLogs); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); if (ab != null) { ab.setTitle(R.string.flashing); } setFloating(); + if (!Shell.rootAccess()) + reboot.setVisibility(View.GONE); - flashLogs.setAdapter(new FlashLogAdapter()); + flashLogs.setAdapter(new FlashLogAdapter(rootShellOutput)); // We must receive a Uri of the target zip - Uri uri = getIntent().getData(); + Intent intent = getIntent(); + Uri uri = intent.getData(); - new FlashZip(this, uri, rootShellOutput) - .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) - .exec(); + switch (getIntent().getStringExtra(SET_ACTION)) { + case FLASH_ZIP: + new FlashZip(this, uri, rootShellOutput) + .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) + .exec(); + break; + case PATCH_BOOT: + new PatchBootImage(this, uri, intent.getParcelableExtra(SET_BOOT_URI), rootShellOutput) + .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) + .exec(); + } } @Override @@ -65,7 +86,13 @@ public class FlashActivity extends Activity { // Prevent user accidentally press back button } - private class FlashLogAdapter extends RecyclerView.Adapter { + private static class FlashLogAdapter extends RecyclerView.Adapter { + + private List mList; + + FlashLogAdapter(List list) { + mList = list; + } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { @@ -76,16 +103,16 @@ public class FlashActivity extends Activity { @Override public void onBindViewHolder(ViewHolder holder, int position) { - holder.text.setText(rootShellOutput.get(position)); + holder.text.setText(mList.get(position)); } @Override public int getItemCount() { - return rootShellOutput.size(); + return mList.size(); } } - public class ViewHolder extends RecyclerView.ViewHolder { + public static class ViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.textView) TextView text; diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 5b0fa5d0f..6aa0af7a2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -1,5 +1,7 @@ package com.topjohnwu.magisk; +import android.app.Activity; +import android.app.AlertDialog; import android.app.NotificationManager; import android.app.ProgressDialog; import android.content.Context; @@ -49,15 +51,15 @@ import butterknife.Unbinder; public class MagiskFragment extends Fragment implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView { - public static final String SHOW_DIALOG = "dialog"; - private static final String UNINSTALLER = "magisk_uninstaller.sh"; private static final String UTIL_FUNCTIONS= "util_functions.sh"; + private static final int SELECT_BOOT_IMG = 3; private Container expandableContainer = new Container(); private MagiskManager magiskManager; private Unbinder unbinder; + private static boolean shownDialog = false; @BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout; @@ -108,6 +110,7 @@ public class MagiskFragment extends Fragment @OnClick(R.id.install_button) public void install() { + shownDialog = true; String bootImage = null; if (Shell.rootAccess()) { if (magiskManager.bootBlock != null) { @@ -117,54 +120,83 @@ public class MagiskFragment extends Fragment if (idx > 0) { bootImage = magiskManager.blockList.get(idx - 1); } else { - SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG).show(); + SnackbarMaker.make(getActivity(), + R.string.manual_boot_image, Snackbar.LENGTH_LONG).show(); return; } } } + final String boot = bootImage; ((NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll(); - final String finalBootImage = bootImage; String filename = "Magisk-v" + magiskManager.remoteMagiskVersionString + ".zip"; new AlertDialogBuilder(getActivity()) - .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) - .setMessage(getString(R.string.repo_install_msg, filename)) - .setCancelable(true) - .setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download, - (d, i) -> - Utils.dlAndReceive( - getActivity(), - new DownloadReceiver() { - private String boot = finalBootImage; - private boolean enc = keepEncChkbox.isChecked(); - private boolean verity = keepVerityChkbox.isChecked(); - - @Override - public void onDownloadDone(Uri uri) { - if (Shell.rootAccess()) { - getShell().su_raw( - "rm -f /dev/.magisk", - "echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk", - "echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk", - "echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk" - ); - startActivity(new Intent(getActivity(), FlashActivity.class).setData(uri)); - } else { - Utils.showUriSnack(getActivity(), uri); - } - } - }, - magiskManager.magiskLink, - Utils.getLegalFilename(filename)) - ) - .setNeutralButton(R.string.release_notes, (d, i) -> { - if (magiskManager.releaseNoteLink != null) { - Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink)); - openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - magiskManager.startActivity(openReleaseNoteLink); + .setTitle(getString(R.string.repo_install_title, getString(R.string.magisk))) + .setMessage(getString(R.string.repo_install_msg, filename)) + .setCancelable(true) + .setPositiveButton( + R.string.install, + (d, i) -> { + List options = new ArrayList<>(); + options.add(getString(R.string.download_zip_only)); + options.add(getString(R.string.patch_boot_file)); + if (Shell.rootAccess()) { + options.add(getString(R.string.direct_install)); } - }) - .setNegativeButton(R.string.no_thanks, null) - .show(); + new AlertDialog.Builder(getActivity()) + .setTitle(R.string.select_method) + .setItems( + options.toArray(new String [0]), + (dialog, idx) -> { + DownloadReceiver receiver = null; + switch (idx) { + case 1: + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + startActivityForResult(intent, SELECT_BOOT_IMG); + return; + case 0: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + Utils.showUriSnack(getActivity(), uri); + } + }; + break; + case 2: + receiver = new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + getShell().su_raw( + "echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk", + "echo \"KEEPFORCEENCRYPT=" + keepEncChkbox.isChecked() + "\" >> /dev/.magisk", + "echo \"KEEPVERITY=" + keepVerityChkbox.isChecked() + "\" >> /dev/.magisk" + ); + Intent intent = new Intent(getActivity(), FlashActivity.class); + intent.setData(uri).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP); + startActivity(intent); + } + }; + break; + } + Utils.dlAndReceive( + getActivity(), + receiver, + magiskManager.magiskLink, + Utils.getLegalFilename(filename) + ); + } + ).show(); + } + ) + .setNeutralButton(R.string.release_notes, (d, i) -> { + if (magiskManager.releaseNoteLink != null) { + Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink)); + openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + magiskManager.startActivity(openReleaseNoteLink); + } + }) + .setNegativeButton(R.string.no_thanks, null) + .show(); } @OnClick(R.id.uninstall_button) @@ -172,7 +204,7 @@ public class MagiskFragment extends Fragment new AlertDialogBuilder(getActivity()) .setTitle(R.string.uninstall_magisk_title) .setMessage(R.string.uninstall_magisk_msg) - .setPositiveButton(R.string.yes, (dialogInterface, i) -> { + .setPositiveButton(R.string.yes, (d, i) -> { try { InputStream in = magiskManager.getAssets().open(UNINSTALLER); File uninstaller = new File(magiskManager.getCacheDir(), UNINSTALLER); @@ -254,6 +286,8 @@ public class MagiskFragment extends Fragment magiskManager.remoteMagiskVersionCode = -1; collapse(); + shownDialog = false; + // Trigger state check if (Utils.checkNetworkStatus(magiskManager)) { new CheckUpdates(getActivity()).exec(); @@ -262,6 +296,28 @@ public class MagiskFragment extends Fragment } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == SELECT_BOOT_IMG && resultCode == Activity.RESULT_OK && data != null) { + Utils.dlAndReceive( + getActivity(), + new DownloadReceiver() { + @Override + public void onDownloadDone(Uri uri) { + // Get the URI of the selected file + Intent intent = new Intent(getActivity(), FlashActivity.class); + intent.setData(uri) + .putExtra(FlashActivity.SET_BOOT_URI, data.getData()) + .putExtra(FlashActivity.SET_ACTION, FlashActivity.PATCH_BOOT); + startActivity(intent); + } + }, + magiskManager.magiskLink, + Utils.getLegalFilename("Magisk-v" + magiskManager.remoteMagiskVersionString + ".zip") + ); + } + } + @Override public void onTopicPublished(Topic topic) { if (topic == magiskManager.updateCheckDone) { @@ -341,7 +397,7 @@ public class MagiskFragment extends Fragment rootStatusIcon.setColorFilter(color); if (!Shell.rootAccess()) { - installText.setText(R.string.download); + installText.setText(R.string.install); } else { if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode) { installText.setText(R.string.update); @@ -384,7 +440,7 @@ public class MagiskFragment extends Fragment magiskUpdateProgress.setVisibility(View.GONE); mSwipeRefreshLayout.setRefreshing(false); - if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode) + if (magiskManager.remoteMagiskVersionCode > magiskManager.magiskVersionCode && !shownDialog) install(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 0df668a20..76ce9944f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -87,7 +87,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber { if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) { // Get the URI of the selected file Intent intent = new Intent(getActivity(), FlashActivity.class); - intent.setData(data.getData()).putExtra("ACTION", "flash"); + intent.setData(data.getData()).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP); startActivity(intent); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 9a7b91a27..90e0d15cf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -139,6 +139,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { if (!Shell.rootAccess()) { prefScreen.removePreference(magiskCategory); prefScreen.removePreference(suCategory); + generalCatagory.removePreference(hideManager); } else { if (!magiskManager.isSuClient) { prefScreen.removePreference(suCategory); diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java index 74b22c067..ebbdd0999 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java @@ -18,7 +18,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.List; -public class FlashZip extends ParallelTask { +public class FlashZip extends ParallelTask { private Uri mUri; private File mCachedFile, mScriptFile, mCheckFile; @@ -40,7 +40,7 @@ public class FlashZip extends ParallelTask { } private boolean unzipAndCheck() throws Exception { - ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android"); + ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", false); List ret = Utils.readFile(getShell(), mCheckFile.getPath()); return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK"); } @@ -52,7 +52,7 @@ public class FlashZip extends ParallelTask { } @Override - protected void onProgressUpdate(String... values) { + protected void onProgressUpdate(Void... values) { mList.updateView(); } @@ -61,18 +61,18 @@ public class FlashZip extends ParallelTask { MagiskManager magiskManager = getMagiskManager(); if (magiskManager == null) return -1; try { - mList.add(magiskManager.getString(R.string.copying_msg)); + mList.add("- Copying zip to temp directory"); mCachedFile.delete(); try ( InputStream in = magiskManager.getContentResolver().openInputStream(mUri); - OutputStream outputStream = new FileOutputStream(mCachedFile) + OutputStream out = new FileOutputStream(mCachedFile) ) { if (in == null) throw new FileNotFoundException(); byte buffer[] = new byte[1024]; int length; while ((length = in.read(buffer)) > 0) - outputStream.write(buffer, 0, length); + out.write(buffer, 0, length); } catch (FileNotFoundException e) { mList.add("! Invalid Uri"); throw e; @@ -81,7 +81,7 @@ public class FlashZip extends ParallelTask { throw e; } if (!unzipAndCheck()) return 0; - mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename)); + mList.add("- Installing " + mFilename); getShell().su(mList, "BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile + " && echo 'Success!' || echo 'Failed!'" diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/PatchBootImage.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/PatchBootImage.java new file mode 100644 index 000000000..ad6cfb75e --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/PatchBootImage.java @@ -0,0 +1,145 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.text.TextUtils; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.utils.AdaptiveList; +import com.topjohnwu.magisk.utils.ZipUtils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.List; + +public class PatchBootImage extends ParallelTask { + + private Uri mBootImg, mZip; + private AdaptiveList mList; + private File dest; + + public PatchBootImage(Activity context, Uri zip, Uri boot, AdaptiveList list) { + super(context); + mBootImg = boot; + mList = list; + mZip = zip; + dest = new File(Environment.getExternalStorageDirectory() + "/MagiskManager/" + "patched_boot.img"); + } + + @Override + protected void onPreExecute() { + // UI updates must run in the UI thread + mList.setCallback(this::publishProgress); + } + + @Override + protected void onProgressUpdate(Void... values) { + mList.updateView(); + } + + @Override + protected Boolean doInBackground(Void... voids) { + MagiskManager magiskManager = getMagiskManager(); + if (magiskManager == null) return false; + + File install = new File(magiskManager.getApplicationInfo().dataDir, "install"); + getShell().sh_raw("rm -rf " + install); + + List abis = Arrays.asList(Build.SUPPORTED_ABIS); + String arch; + if (abis.contains("x86_64")) arch = "x64"; + else if (abis.contains("arm64-v8a")) arch = "arm64"; + else if (abis.contains("x86")) arch = "x86"; + else arch = "arm"; + mList.add("- Device platform: " + arch); + + try { + // Unzip files + mList.add("- Extracting files"); + try (InputStream in = magiskManager.getContentResolver().openInputStream(mZip)) { + if (in == null) throw new FileNotFoundException(); + BufferedInputStream buf = new BufferedInputStream(in); + buf.mark(Integer.MAX_VALUE); + ZipUtils.unzip(buf, install, arch, true); + buf.reset(); + ZipUtils.unzip(buf, install, "common", true); + buf.reset(); + ZipUtils.unzip(buf, install, "chromeos", false); + buf.reset(); + ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true); + } catch (FileNotFoundException e) { + mList.add("! Invalid Uri"); + throw e; + } catch (Exception e) { + mList.add("! Cannot unzip zip"); + throw e; + } + + // Copy boot image + File boot = new File(install, "boot.img"); + try ( + InputStream in = magiskManager.getContentResolver().openInputStream(mBootImg); + OutputStream out = new FileOutputStream(boot); + ) { + if (in == null) throw new FileNotFoundException(); + byte buffer[] = new byte[1024]; + int length; + while ((length = in.read(buffer)) > 0) + out.write(buffer, 0, length); + } catch (FileNotFoundException e) { + mList.add("! Invalid Uri"); + throw e; + } catch (IOException e) { + mList.add("! Copy failed"); + throw e; + } + + mList.add("- Use boot image: " + boot); + + // Patch boot image + getShell().sh(mList, + "chmod -R 755 " + install, + "cd " + install, + "sh update-binary indep boot_patch.sh " + boot + + " && echo 'Success!' || echo 'Failed!'" + ); + + if (!TextUtils.equals(mList.get(mList.size() - 1), "Success!")) + return false; + + // Move boot image + File source = new File(install, "new-boot.img"); + dest.getParentFile().mkdirs(); + getShell().sh_raw("mv " + source + " " + dest); + + // Finals + getShell().sh_raw( + "mv bin/busybox busybox", + "rm -rf bin *.img update-binary"); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + if (result) { + mList.add(""); + mList.add("*********************************"); + mList.add(" Patched Boot Image is placed in "); + mList.add(" " + dest + " "); + mList.add("*********************************"); + } + super.onPostExecute(result); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java index 1e1e8d6a3..dc7c8ca93 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java @@ -94,12 +94,15 @@ public class ProcessRepoZip extends ParallelTask { progressDialog.dismiss(); if (result) { if (Shell.rootAccess() && mInstall) { - activity.startActivity(new Intent(activity, FlashActivity.class).setData(mUri)); + Intent intent = new Intent(getActivity(), FlashActivity.class); + intent.setData(mUri).putExtra(FlashActivity.SET_ACTION, FlashActivity.FLASH_ZIP); + activity.startActivity(intent); } else { Utils.showUriSnack(activity, mUri); } } else { Utils.getMagiskManager(activity).toast(R.string.process_error, Toast.LENGTH_LONG); } + super.onPostExecute(result); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java index 6fd2d5ea0..a65a5b190 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java @@ -156,34 +156,38 @@ public class ZipUtils { } } - public static void unzip(File file, File folder, String path) throws Exception { - int count; - FileOutputStream out; - File dest; - InputStream is; - JarEntry entry; + public static void unzip(File zip, File folder, String path, boolean junkPath) throws Exception { + JarInputStream in = new JarInputStream(new FileInputStream(zip)); + unzip(in, folder, path, junkPath); + in.close(); + } + + public static void unzip(InputStream zip, File folder, String path, boolean junkPath) throws Exception { byte data[] = new byte[4096]; - try (JarFile zipfile = new JarFile(file)) { - Enumeration e = zipfile.entries(); - while(e.hasMoreElements()) { - entry = e.nextElement(); - if (!entry.getName().contains(path) || entry.isDirectory()){ + try { + JarInputStream zipfile = new JarInputStream(zip); + JarEntry entry; + while ((entry = zipfile.getNextJarEntry()) != null) { + if (!entry.getName().startsWith(path) || entry.isDirectory()){ // Ignore directories, only create files continue; } - Logger.dev("ZipUtils: Extracting: " + entry); - is = zipfile.getInputStream(entry); - dest = new File(folder, entry.getName()); - if (dest.getParentFile().mkdirs()) { - dest.createNewFile(); + String name; + if (junkPath) { + name = entry.getName().substring(entry.getName().lastIndexOf('/') + 1); + } else { + name = entry.getName(); } - out = new FileOutputStream(dest); - while ((count = is.read(data)) != -1) { + Logger.dev("ZipUtils: Extracting: " + entry); + File dest = new File(folder, name); + dest.getParentFile().mkdirs(); + FileOutputStream out = new FileOutputStream(dest); + int count; + while ((count = zipfile.read(data)) != -1) { out.write(data, 0, count); } out.flush(); out.close(); - is.close(); } } catch(Exception e) { e.printStackTrace(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d5c3a7ce8..ee567dc70 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,6 +138,10 @@ Flashing Hiding Magisk Manager… Hide Magisk Manager failed… + Download Zip Only + Patch Boot Image File + Direct Install (Recommend) + Select Method General