From 3a74729ecc4615a9c510671cb11a1efcfb9f73c5 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 18 Nov 2017 03:55:47 +0800 Subject: [PATCH] Add saving logs feature for installation --- .../com/topjohnwu/magisk/FlashActivity.java | 87 +++++++++++-------- .../topjohnwu/magisk/MagiskLogFragment.java | 1 - .../com/topjohnwu/magisk/asyncs/FlashZip.java | 42 +++++---- .../magisk/asyncs/InstallMagisk.java | 66 +++++++------- .../magisk/container/CallbackList.java | 4 +- app/src/main/res/layout/activity_flash.xml | 8 ++ app/src/main/res/menu/menu_log.xml | 2 +- app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-el/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-et/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-hr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-ja/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-pt-rPT/strings.xml | 11 ++- app/src/main/res/values-ro/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 2 +- app/src/main/res/values-tr/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values-vi/strings.xml | 2 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values-zh-rTW/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 31 files changed, 154 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java index 83d4ce369..07148acb2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/FlashActivity.java @@ -11,6 +11,7 @@ import android.widget.Button; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; +import android.widget.Toast; import com.topjohnwu.magisk.asyncs.FlashZip; import com.topjohnwu.magisk.asyncs.InstallMagisk; @@ -19,6 +20,14 @@ import com.topjohnwu.magisk.container.CallbackList; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.Shell; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; + import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; @@ -27,32 +36,50 @@ public class FlashActivity extends Activity { @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.txtLog) TextView flashLogs; - @BindView(R.id.button_panel) LinearLayout buttonPanel; - @BindView(R.id.reboot) Button reboot; + @BindView(R.id.button_panel) public LinearLayout buttonPanel; + @BindView(R.id.reboot) public Button reboot; @BindView(R.id.scrollView) ScrollView sv; + private List logs; + @OnClick(R.id.no_thanks) - public void dismiss() { + void dismiss() { finish(); } @OnClick(R.id.reboot) - public void reboot() { + void reboot() { Shell.su_raw("reboot"); } + @OnClick(R.id.save_logs) + void saveLogs() { + Calendar now = Calendar.getInstance(); + String filename = String.format(Locale.US, + "install_log_%04d%02d%02d_%02d:%02d:%02d.log", + now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, + now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY), + now.get(Calendar.MINUTE), now.get(Calendar.SECOND)); + + File logFile = new File(Const.EXTERNAL_PATH + "/logs", filename); + logFile.getParentFile().mkdirs(); + try (FileWriter writer = new FileWriter(logFile)) { + for (String s : logs) { + writer.write(s); + writer.write('\n'); + } + } catch (IOException e) { + e.printStackTrace(); + return; + } + MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flash); ButterKnife.bind(this); - CallbackList rootShellOutput = new CallbackList() { - @Override - public synchronized void onAddElement() { - flashLogs.setText(TextUtils.join("\n", this)); - sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10); - } - }; setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); if (ab != null) { @@ -63,6 +90,16 @@ public class FlashActivity extends Activity { if (!Shell.rootAccess()) reboot.setVisibility(View.GONE); + logs = new ArrayList<>(); + List console = new CallbackList() { + @Override + public synchronized void onAddElement(String e) { + logs.add(e); + flashLogs.setText(TextUtils.join("\n", this)); + sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10); + } + }; + // We must receive a Uri of the target zip Intent intent = getIntent(); Uri uri = intent.getData(); @@ -70,35 +107,17 @@ public class FlashActivity extends Activity { boolean keepEnc = intent.getBooleanExtra(Const.Key.FLASH_SET_ENC, false); boolean keepVerity = intent.getBooleanExtra(Const.Key.FLASH_SET_VERITY, false); - switch (getIntent().getStringExtra(Const.Key.FLASH_ACTION)) { + switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) { case Const.Value.FLASH_ZIP: - new FlashZip(this, uri, rootShellOutput) - .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) - .exec(); + new FlashZip(this, uri, console, logs).exec(); break; case Const.Value.PATCH_BOOT: - new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)) - .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) + new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)) .exec(); break; case Const.Value.FLASH_MAGISK: - String boot = intent.getStringExtra(Const.Key.FLASH_SET_BOOT); - if (getMagiskManager().remoteMagiskVersionCode < 1370) { - // Use legacy installation method - Shell.su_raw( - "echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk", - "echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk", - "echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk" - ); - new FlashZip(this, uri, rootShellOutput) - .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) - .exec(); - } else { - // Use new installation method - new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, boot) - .setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE)) - .exec(); - } + new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, intent.getStringExtra(Const.Key.FLASH_SET_BOOT)) + .exec(); break; } } diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java index e95318d9d..92e1de515 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java @@ -1,7 +1,6 @@ package com.topjohnwu.magisk; import android.Manifest; -import android.annotation.SuppressLint; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; 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 cfc43cc31..3795d4786 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java @@ -3,9 +3,10 @@ package com.topjohnwu.magisk.asyncs; import android.app.Activity; import android.net.Uri; import android.text.TextUtils; +import android.view.View; +import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -25,12 +26,13 @@ public class FlashZip extends ParallelTask { private Uri mUri; private File mCachedFile; - private List mList; + private List console, logs; - public FlashZip(Activity context, Uri uri, List list) { + public FlashZip(Activity context, Uri uri, List console, List logs) { super(context); mUri = uri; - mList = list; + this.console = console; + this.logs = logs; mCachedFile = new File(context.getCacheDir(), "install.zip"); } @@ -44,7 +46,7 @@ public class FlashZip extends ParallelTask { protected Integer doInBackground(Void... voids) { MagiskManager mm = MagiskManager.get(); try { - mList.add("- Copying zip to temp directory"); + console.add("- Copying zip to temp directory"); mCachedFile.delete(); try ( @@ -55,48 +57,52 @@ public class FlashZip extends ParallelTask { InputStream buf= new BufferedInputStream(in); Utils.inToOut(buf, out); } catch (FileNotFoundException e) { - mList.add("! Invalid Uri"); + console.add("! Invalid Uri"); throw e; } catch (IOException e) { - mList.add("! Cannot copy to cache"); + console.add("! Cannot copy to cache"); throw e; } if (!unzipAndCheck()) return 0; - mList.add("- Installing " + Utils.getNameFromUri(mm, mUri)); - Shell.su(mList, + console.add("- Installing " + Utils.getNameFromUri(mm, mUri)); + Shell.getShell().run(console, logs, "cd " + mCachedFile.getParent(), - "BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + - " && echo 'Success!' || echo 'Failed!'" + "BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + " || echo 'Failed!'" ); - if (TextUtils.equals(mList.get(mList.size() - 1), "Success!")) - return 1; + + if (TextUtils.equals(console.get(console.size() - 1), "Failed!")) + return -1; + } catch (Exception e) { e.printStackTrace(); + return -1; } - return -1; + console.add("- All done!"); + return 1; } // -1 = error, manual install; 0 = invalid zip; 1 = success @Override protected void onPostExecute(Integer result) { - MagiskManager mm = MagiskManager.get(); + FlashActivity activity = (FlashActivity) getActivity(); Shell.su_raw( "rm -rf " + mCachedFile.getParent(), "rm -rf " + Const.TMP_FOLDER_PATH ); switch (result) { case -1: - mList.add(mm.getString(R.string.install_error)); + console.add("! Installation failed"); Utils.showUriSnack(getActivity(), mUri); break; case 0: - mList.add(mm.getString(R.string.invalid_zip)); + console.add("! This zip is not a Magisk Module!"); break; case 1: // Success new LoadModules().exec(); break; } - super.onPostExecute(result); + activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE); + activity.buttonPanel.setVisibility(View.VISIBLE); } } 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 c5b3ab84f..1bb0f2e64 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java @@ -5,8 +5,10 @@ import android.content.res.AssetManager; import android.net.Uri; import android.os.Build; import android.text.TextUtils; +import android.view.View; import com.topjohnwu.crypto.SignBoot; +import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.TarEntry; import com.topjohnwu.magisk.utils.Const; @@ -35,27 +37,28 @@ public class InstallMagisk extends ParallelTask { private static final int DIRECT_MODE = 1; private Uri mBootImg, mZip; - private List mList; + private List console, logs; private String mBootLocation; private boolean mKeepEnc, mKeepVerity; private int mode; - private InstallMagisk(Activity context, List list, Uri zip, boolean enc, boolean verity) { + private InstallMagisk(Activity context, List console, List logs, Uri zip, boolean enc, boolean verity) { super(context); - mList = list; + this.console = console; + this.logs = logs; mZip = zip; mKeepEnc = enc; mKeepVerity = verity; } - public InstallMagisk(Activity context, List list, Uri zip, boolean enc, boolean verity, Uri boot) { - this(context, list, zip, enc, verity); + public InstallMagisk(Activity context, List console, List logs, Uri zip, boolean enc, boolean verity, Uri boot) { + this(context, console, logs, zip, enc, verity); mBootImg = boot; mode = PATCH_MODE; } - public InstallMagisk(Activity context, List list, Uri zip, boolean enc, boolean verity, String boot) { - this(context, list, zip, enc, verity); + public InstallMagisk(Activity context, List console, List logs, Uri zip, boolean enc, boolean verity, String boot) { + this(context, console, logs, zip, enc, verity); mBootLocation = boot; mode = DIRECT_MODE; } @@ -77,11 +80,11 @@ public class InstallMagisk extends ParallelTask { else if (abis.contains("arm64-v8a")) arch = "arm64"; else if (abis.contains("x86")) arch = "x86"; else arch = "arm"; - mList.add("- Device platform: " + arch); + console.add("- Device platform: " + arch); try { // Unzip files - mList.add("- Extracting files"); + console.add("- Extracting files"); try (InputStream in = mm.getContentResolver().openInputStream(mZip)) { if (in == null) throw new FileNotFoundException(); BufferedInputStream buf = new BufferedInputStream(in); @@ -95,17 +98,17 @@ public class InstallMagisk extends ParallelTask { ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true); buf.close(); } catch (FileNotFoundException e) { - mList.add("! Invalid Uri"); + console.add("! Invalid Uri"); throw e; } catch (Exception e) { - mList.add("! Cannot unzip zip"); + console.add("! Cannot unzip zip"); throw e; } File boot = new File(install, "boot.img"); switch (mode) { case PATCH_MODE: - mList.add("- Use boot image: " + boot); + console.add("- Use boot image: " + boot); // Copy boot image to local try ( InputStream in = mm.getContentResolver().openInputStream(mBootImg); @@ -129,19 +132,19 @@ public class InstallMagisk extends ParallelTask { } Utils.inToOut(source, out); } catch (FileNotFoundException e) { - mList.add("! Invalid Uri"); + console.add("! Invalid Uri"); throw e; } catch (IOException e) { - mList.add("! Copy failed"); + console.add("! Copy failed"); throw e; } break; case DIRECT_MODE: - mList.add("- Use boot image: " + mBootLocation); + console.add("- Use boot image: " + mBootLocation); if (boot.createNewFile()) { Shell.su("cat " + mBootLocation + " > " + boot); } else { - mList.add("! Dump boot image failed"); + console.add("! Dump boot image failed"); return false; } break; @@ -153,10 +156,10 @@ public class InstallMagisk extends ParallelTask { try (InputStream in = new FileInputStream(boot)) { isSigned = SignBoot.verifySignature(in, null); if (isSigned) { - mList.add("- Signed boot image detected"); + console.add("- Signed boot image detected"); } } catch (Exception e) { - mList.add("! Unable to check signature"); + console.add("! Unable to check signature"); throw e; } @@ -168,12 +171,12 @@ public class InstallMagisk extends ParallelTask { shell = Shell.getShell(); // Patch boot image - shell.run(mList, null, + shell.run(console, logs, "cd " + install, "KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " + "update-binary indep boot_patch.sh " + boot + " || echo 'Failed!'"); - if (TextUtils.equals(mList.get(mList.size() - 1), "Failed!")) + if (TextUtils.equals(console.get(console.size() - 1), "Failed!")) return false; shell.run(null, null, @@ -185,7 +188,7 @@ public class InstallMagisk extends ParallelTask { File patched_boot = new File(install.getParent(), "new-boot.img"); if (isSigned) { - mList.add("- Signing boot image"); + console.add("- Signing boot image"); File signed = new File(install.getParent(), "signed.img"); AssetManager assets = mm.getAssets(); try ( @@ -217,15 +220,15 @@ public class InstallMagisk extends ParallelTask { } break; } - mList.add(""); - mList.add("*********************************"); - mList.add(" Patched Boot Image is placed in "); - mList.add(" " + dest + " "); - mList.add("*********************************"); + console.add(""); + console.add("*********************************"); + console.add(" Patched Boot Image is placed in "); + console.add(" " + dest + " "); + console.add("*********************************"); break; case DIRECT_MODE: // Direct flash boot image and patch dtbo if possible - Shell.su(mList, + Shell.getShell().run(console, logs, "rm -rf /data/magisk/*", "mkdir -p /data/magisk 2>/dev/null", "mv -f " + install + "/* /data/magisk", @@ -238,7 +241,7 @@ public class InstallMagisk extends ParallelTask { return false; } - mList.add("- All done!"); + console.add("- All done!"); } catch (Exception e) { e.printStackTrace(); return false; @@ -248,6 +251,11 @@ public class InstallMagisk extends ParallelTask { @Override protected void onPostExecute(Boolean result) { - super.onPostExecute(result); + FlashActivity activity = (FlashActivity) getActivity(); + if (!result) { + console.add("! Installation failed"); + activity.reboot.setVisibility(View.GONE); + } + activity.buttonPanel.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/container/CallbackList.java b/app/src/main/java/com/topjohnwu/magisk/container/CallbackList.java index dbc492ff3..0ee88e1d4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/container/CallbackList.java +++ b/app/src/main/java/com/topjohnwu/magisk/container/CallbackList.java @@ -12,11 +12,11 @@ public abstract class CallbackList extends ArrayList { handler = new Handler(); } - public abstract void onAddElement(); + public abstract void onAddElement(E e); public synchronized boolean add(E e) { boolean ret = super.add(e); - handler.post(this::onAddElement); + handler.post(() -> onAddElement(e)); return ret; } } diff --git a/app/src/main/res/layout/activity_flash.xml b/app/src/main/res/layout/activity_flash.xml index b4e81a883..fe22f99b4 100644 --- a/app/src/main/res/layout/activity_flash.xml +++ b/app/src/main/res/layout/activity_flash.xml @@ -50,6 +50,14 @@ android:layout_weight="1" android:text="@string/close" /> +