mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-06-12 13:17:39 +02:00
Add saving logs feature for installation
This commit is contained in:
@ -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<String> 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<String> rootShellOutput = new CallbackList<String>() {
|
||||
@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<String> console = new CallbackList<String>() {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<Void, Void, Integer> {
|
||||
|
||||
private Uri mUri;
|
||||
private File mCachedFile;
|
||||
private List<String> mList;
|
||||
private List<String> console, logs;
|
||||
|
||||
public FlashZip(Activity context, Uri uri, List<String> list) {
|
||||
public FlashZip(Activity context, Uri uri, List<String> console, List<String> 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<Void, Void, Integer> {
|
||||
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<Void, Void, Integer> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Void, Void, Boolean> {
|
||||
private static final int DIRECT_MODE = 1;
|
||||
|
||||
private Uri mBootImg, mZip;
|
||||
private List<String> mList;
|
||||
private List<String> console, logs;
|
||||
private String mBootLocation;
|
||||
private boolean mKeepEnc, mKeepVerity;
|
||||
private int mode;
|
||||
|
||||
private InstallMagisk(Activity context, List<String> list, Uri zip, boolean enc, boolean verity) {
|
||||
private InstallMagisk(Activity context, List<String> console, List<String> 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<String> list, Uri zip, boolean enc, boolean verity, Uri boot) {
|
||||
this(context, list, zip, enc, verity);
|
||||
public InstallMagisk(Activity context, List<String> console, List<String> 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<String> list, Uri zip, boolean enc, boolean verity, String boot) {
|
||||
this(context, list, zip, enc, verity);
|
||||
public InstallMagisk(Activity context, List<String> console, List<String> 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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
}
|
||||
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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
}
|
||||
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<Void, Void, Boolean> {
|
||||
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<Void, Void, Boolean> {
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ public abstract class CallbackList<E> extends ArrayList<E> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user