Some refinements
This commit is contained in:
parent
3b20747192
commit
4daea7d7e6
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user