From 4daea7d7e666f3cdd5cfaa98df66a869a0c5a440 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 23 Nov 2016 22:38:15 +0800 Subject: [PATCH] Some refinements --- .../magisk/adapters/ReposAdapter.java | 45 ++----------------- .../magisk/receivers/DownloadReceiver.java | 2 +- .../magisk/receivers/RepoDlReceiver.java | 43 ++++++++++++++++++ .../com/topjohnwu/magisk/utils/Async.java | 38 ++++++---------- .../com/topjohnwu/magisk/utils/Utils.java | 15 +++++++ .../com/topjohnwu/magisk/utils/ZipUtils.java | 14 +++--- 6 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java index e5f2b5578..ced32f170 100644 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/adapters/ReposAdapter.java @@ -22,14 +22,13 @@ import android.widget.TextView; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.magisk.receivers.RepoDlReceiver; import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.Utils.ByteArrayInOutStream; import com.topjohnwu.magisk.utils.WebWindow; import com.topjohnwu.magisk.utils.ZipUtils; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.OutputStream; import java.util.List; @@ -57,7 +56,7 @@ public class ReposAdapter extends RecyclerView.Adapter String theme = PreferenceManager.getDefaultSharedPreferences(context).getString("theme", ""); if (theme.equals("Dark")) { - builder = new AlertDialog.Builder(context,R.style.AlertDialog_dh); + builder = new AlertDialog.Builder(context, R.style.AlertDialog_dh); } else { builder = new AlertDialog.Builder(context); } @@ -102,43 +101,7 @@ public class ReposAdapter extends RecyclerView.Adapter .setCancelable(true) .setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive( context, - new DownloadReceiver() { - @Override - public void task(Uri uri) { - // Flash the zip - new Async.FlashZIP(mContext, uri, mFilename){ - @Override - protected void preProcessing() throws Throwable { - // Process and sign the zip - publishProgress(mContext.getString(R.string.zip_install_process_zip_msg)); - try { - ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); - ByteArrayInputStream inBuffer; - - // First remove top folder (the folder with the repo name) in Github source zip - ZipUtils.removeTopFolder(mContext.getContentResolver().openInputStream(mUri), outBuffer); - inBuffer = new ByteArrayInputStream(outBuffer.toByteArray()); - outBuffer.reset(); - - // Then sign the zip for the first time - ZipUtils.signZip(mContext, inBuffer, outBuffer, false); - - // Call zipadjust through JNI - inBuffer = new ByteArrayInputStream(ZipUtils.zipAdjust(outBuffer.toByteArray(), outBuffer.size())); - outBuffer.reset(); - - // Finally, sign the whole zip file again - ZipUtils.signZip(mContext, inBuffer, outBuffer, true); - - // Write it back to the downloaded zip - OutputStream out = mContext.getContentResolver().openOutputStream(mUri); - outBuffer.writeTo(out); - out.close(); - } catch (IOException ignored) {} - } - }.exec(); - } - }, + new RepoDlReceiver(), repo.getZipUrl(), Utils.getLegalFilename(filename))) .setNegativeButton(R.string.no_thanks, null) diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java index 841f91456..3c2cf976f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/DownloadReceiver.java @@ -52,5 +52,5 @@ public abstract class DownloadReceiver extends BroadcastReceiver { mFilename = filename; } - public void task(Uri uri) {} + public abstract void task(Uri uri); } diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java new file mode 100644 index 000000000..0c2043e4d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java @@ -0,0 +1,43 @@ +package com.topjohnwu.magisk.receivers; + +import android.net.Uri; + +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.Utils.ByteArrayInOutStream; +import com.topjohnwu.magisk.utils.ZipUtils; + +import java.io.OutputStream; + +public class RepoDlReceiver extends DownloadReceiver { + @Override + public void task(Uri uri) { + // Flash the zip + new Async.FlashZIP(mContext, uri, mFilename){ + @Override + protected void preProcessing() throws Throwable { + // Process and sign the zip + publishProgress(mContext.getString(R.string.zip_install_process_zip_msg)); + ByteArrayInOutStream buffer = new ByteArrayInOutStream(); + + // First remove top folder (the folder with the repo name) in Github source zip + ZipUtils.removeTopFolder(mContext.getContentResolver().openInputStream(mUri), buffer); + + // Then sign the zip for the first time + ZipUtils.signZip(mContext, buffer.getInputStream(), buffer, false); + + // Adjust the zip to prevent unzip issues + ZipUtils.adjustZip(buffer); + + // Finally, sign the whole zip file again + ZipUtils.signZip(mContext, buffer.getInputStream(), buffer, true); + + // Write it back to the downloaded zip + OutputStream out = mContext.getContentResolver().openOutputStream(mUri); + buffer.writeTo(out); + out.close(); + } + }.exec(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java index a7c4a7215..148d54d3b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java @@ -7,7 +7,6 @@ import android.content.pm.ApplicationInfo; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; -import android.os.Environment; import android.preference.PreferenceManager; import android.provider.OpenableColumns; import android.support.v7.app.AlertDialog; @@ -21,7 +20,6 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -179,13 +177,13 @@ public class Async { mContext = context; mUri = uri; mFilename = filename; - progress = new ProgressDialog(mContext); } public FlashZIP(Context context, Uri uri) { mContext = context; mUri = uri; - progress = new ProgressDialog(mContext); + + // Try to get the filename ourselves Cursor c = mContext.getContentResolver().query(uri, null, null, null, null); if (c != null) { int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME); @@ -201,32 +199,23 @@ public class Async { } } - private void createFileFromInputStream(InputStream inputStream, File file) throws IOException { - if (file.exists() && !file.delete()) { - throw new IOException(); - } - file.setWritable(true, false); - OutputStream outputStream = new FileOutputStream(file); - byte buffer[] = new byte[1024]; - int length; - - while ((length = inputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - - outputStream.close(); - Logger.dev("FlashZip: File created successfully - " + file.getPath()); - } - protected void preProcessing() throws Throwable {} protected void copyToCache() throws Throwable { try { InputStream in = mContext.getContentResolver().openInputStream(mUri); mCachedFile = new File(mContext.getCacheDir().getAbsolutePath() + "/install.zip"); - mCachedFile.delete(); - Utils.removeItem(mCachedFile.getPath()); - createFileFromInputStream(in, mCachedFile); + if (mCachedFile.exists() && !mCachedFile.delete()) { + throw new IOException(); + } + OutputStream outputStream = new FileOutputStream(mCachedFile); + byte buffer[] = new byte[1024]; + int length; + while ((length = in.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + outputStream.close(); + Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath()); in.close(); } catch (FileNotFoundException e) { Log.e(Logger.LOG_TAG, "FlashZip: Invalid Uri"); @@ -239,6 +228,7 @@ public class Async { @Override protected void onPreExecute() { + progress = new ProgressDialog(mContext); progress.setTitle(R.string.zip_install_progress_title); progress.show(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 545421d2d..8e9763ff0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -14,6 +14,8 @@ import android.widget.Toast; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.receivers.DownloadReceiver; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; @@ -136,4 +138,17 @@ public class Utils { .replace("#", "").replace("@", "").replace("*", ""); } + public static class ByteArrayInOutStream extends ByteArrayOutputStream { + public ByteArrayInputStream getInputStream() { + ByteArrayInputStream in = new ByteArrayInputStream(buf, 0, count); + count = 0; + buf = new byte[32]; + return in; + } + public void setBuffer(byte[] buffer) { + buf = buffer; + count = buffer.length; + } + } + } \ No newline at end of file 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 296bfb529..b89744b45 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java @@ -3,6 +3,8 @@ package com.topjohnwu.magisk.utils; import android.content.Context; import android.util.Pair; +import com.topjohnwu.magisk.utils.Utils.ByteArrayInOutStream; + import org.spongycastle.asn1.ASN1InputStream; import org.spongycastle.asn1.ASN1ObjectIdentifier; import org.spongycastle.asn1.DEROutputStream; @@ -81,6 +83,11 @@ public class ZipUtils { public native static byte[] zipAdjust(byte[] bytes, int size); + // Wrapper function for the JNI function + public static void adjustZip(ByteArrayInOutStream buffer) { + buffer.setBuffer(zipAdjust(buffer.toByteArray(), buffer.size())); + } + public static void removeTopFolder(InputStream in, OutputStream out) { try { JarInputStream source = new JarInputStream(in); @@ -482,7 +489,7 @@ public class ZipUtils { private static void copyFiles(Manifest manifest, JarMap in, JarOutputStream out, long timestamp) throws IOException { Map entries = manifest.getEntries(); - ArrayList names = new ArrayList(entries.keySet()); + ArrayList names = new ArrayList<>(entries.keySet()); Collections.sort(names); for (String name : names) { JarEntry inEntry = in.getJarEntry(name); @@ -588,10 +595,7 @@ public class ZipUtils { copyFiles(manifest, inputJar, outputJar, timestamp); // Don't add Otacert, it's not an OTA // addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash); - signFile(manifest, inputJar, - publicKey, - privateKey, - outputJar); + signFile(manifest, inputJar, publicKey, privateKey, outputJar); signer.notifyClosing(); outputJar.close(); signer.finish();