Some refinements

This commit is contained in:
topjohnwu 2016-11-23 22:38:15 +08:00
parent 3b20747192
commit 4daea7d7e6
6 changed files with 86 additions and 71 deletions

View File

@ -22,14 +22,13 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.receivers.DownloadReceiver;
import com.topjohnwu.magisk.receivers.RepoDlReceiver;
import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.Utils.ByteArrayInOutStream;
import com.topjohnwu.magisk.utils.WebWindow; import com.topjohnwu.magisk.utils.WebWindow;
import com.topjohnwu.magisk.utils.ZipUtils; import com.topjohnwu.magisk.utils.ZipUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List; import java.util.List;
@ -57,7 +56,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
String theme = PreferenceManager.getDefaultSharedPreferences(context).getString("theme", ""); String theme = PreferenceManager.getDefaultSharedPreferences(context).getString("theme", "");
if (theme.equals("Dark")) { if (theme.equals("Dark")) {
builder = new AlertDialog.Builder(context,R.style.AlertDialog_dh); builder = new AlertDialog.Builder(context, R.style.AlertDialog_dh);
} else { } else {
builder = new AlertDialog.Builder(context); builder = new AlertDialog.Builder(context);
} }
@ -102,43 +101,7 @@ public class ReposAdapter extends RecyclerView.Adapter<ReposAdapter.ViewHolder>
.setCancelable(true) .setCancelable(true)
.setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive( .setPositiveButton(R.string.download_install, (dialogInterface, i) -> Utils.dlAndReceive(
context, context,
new DownloadReceiver() { new RepoDlReceiver(),
@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();
}
},
repo.getZipUrl(), repo.getZipUrl(),
Utils.getLegalFilename(filename))) Utils.getLegalFilename(filename)))
.setNegativeButton(R.string.no_thanks, null) .setNegativeButton(R.string.no_thanks, null)

View File

@ -52,5 +52,5 @@ public abstract class DownloadReceiver extends BroadcastReceiver {
mFilename = filename; mFilename = filename;
} }
public void task(Uri uri) {} public abstract void task(Uri uri);
} }

View File

@ -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();
}
}

View File

@ -7,7 +7,6 @@ import android.content.pm.ApplicationInfo;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Environment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
@ -21,7 +20,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -179,13 +177,13 @@ public class Async {
mContext = context; mContext = context;
mUri = uri; mUri = uri;
mFilename = filename; mFilename = filename;
progress = new ProgressDialog(mContext);
} }
public FlashZIP(Context context, Uri uri) { public FlashZIP(Context context, Uri uri) {
mContext = context; mContext = context;
mUri = uri; mUri = uri;
progress = new ProgressDialog(mContext);
// Try to get the filename ourselves
Cursor c = mContext.getContentResolver().query(uri, null, null, null, null); Cursor c = mContext.getContentResolver().query(uri, null, null, null, null);
if (c != null) { if (c != null) {
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME); 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 preProcessing() throws Throwable {}
protected void copyToCache() throws Throwable { protected void copyToCache() throws Throwable {
try { try {
InputStream in = mContext.getContentResolver().openInputStream(mUri); InputStream in = mContext.getContentResolver().openInputStream(mUri);
mCachedFile = new File(mContext.getCacheDir().getAbsolutePath() + "/install.zip"); mCachedFile = new File(mContext.getCacheDir().getAbsolutePath() + "/install.zip");
mCachedFile.delete(); if (mCachedFile.exists() && !mCachedFile.delete()) {
Utils.removeItem(mCachedFile.getPath()); throw new IOException();
createFileFromInputStream(in, mCachedFile); }
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(); in.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e(Logger.LOG_TAG, "FlashZip: Invalid Uri"); Log.e(Logger.LOG_TAG, "FlashZip: Invalid Uri");
@ -239,6 +228,7 @@ public class Async {
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
progress = new ProgressDialog(mContext);
progress.setTitle(R.string.zip_install_progress_title); progress.setTitle(R.string.zip_install_progress_title);
progress.show(); progress.show();
} }

View File

@ -14,6 +14,8 @@ import android.widget.Toast;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.receivers.DownloadReceiver;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -136,4 +138,17 @@ public class Utils {
.replace("#", "").replace("@", "").replace("*", ""); .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;
}
}
} }

View File

@ -3,6 +3,8 @@ package com.topjohnwu.magisk.utils;
import android.content.Context; import android.content.Context;
import android.util.Pair; import android.util.Pair;
import com.topjohnwu.magisk.utils.Utils.ByteArrayInOutStream;
import org.spongycastle.asn1.ASN1InputStream; import org.spongycastle.asn1.ASN1InputStream;
import org.spongycastle.asn1.ASN1ObjectIdentifier; import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.DEROutputStream; import org.spongycastle.asn1.DEROutputStream;
@ -81,6 +83,11 @@ public class ZipUtils {
public native static byte[] zipAdjust(byte[] bytes, int size); 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) { public static void removeTopFolder(InputStream in, OutputStream out) {
try { try {
JarInputStream source = new JarInputStream(in); JarInputStream source = new JarInputStream(in);
@ -482,7 +489,7 @@ public class ZipUtils {
private static void copyFiles(Manifest manifest, private static void copyFiles(Manifest manifest,
JarMap in, JarOutputStream out, long timestamp) throws IOException { JarMap in, JarOutputStream out, long timestamp) throws IOException {
Map<String, Attributes> entries = manifest.getEntries(); Map<String, Attributes> entries = manifest.getEntries();
ArrayList<String> names = new ArrayList<String>(entries.keySet()); ArrayList<String> names = new ArrayList<>(entries.keySet());
Collections.sort(names); Collections.sort(names);
for (String name : names) { for (String name : names) {
JarEntry inEntry = in.getJarEntry(name); JarEntry inEntry = in.getJarEntry(name);
@ -588,10 +595,7 @@ public class ZipUtils {
copyFiles(manifest, inputJar, outputJar, timestamp); copyFiles(manifest, inputJar, outputJar, timestamp);
// Don't add Otacert, it's not an OTA // Don't add Otacert, it's not an OTA
// addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash); // addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash);
signFile(manifest, inputJar, signFile(manifest, inputJar, publicKey, privateKey, outputJar);
publicKey,
privateKey,
outputJar);
signer.notifyClosing(); signer.notifyClosing();
outputJar.close(); outputJar.close();
signer.finish(); signer.finish();