Magisk/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java

275 lines
11 KiB
Java
Raw Normal View History

2017-08-31 03:07:33 +08:00
package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
2017-10-31 16:31:58 +08:00
import android.content.res.AssetManager;
2017-08-31 03:07:33 +08:00
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
2017-08-31 03:07:33 +08:00
2017-10-31 16:31:58 +08:00
import com.topjohnwu.crypto.SignBoot;
import com.topjohnwu.magisk.FlashActivity;
2017-08-31 03:07:33 +08:00
import com.topjohnwu.magisk.MagiskManager;
2017-09-30 03:04:23 +08:00
import com.topjohnwu.magisk.container.TarEntry;
2017-11-06 04:41:23 +08:00
import com.topjohnwu.magisk.utils.Const;
2017-09-04 01:57:45 +08:00
import com.topjohnwu.magisk.utils.Utils;
2017-08-31 03:07:33 +08:00
import com.topjohnwu.magisk.utils.ZipUtils;
2018-01-21 06:07:24 +08:00
import com.topjohnwu.superuser.Shell;
2017-08-31 03:07:33 +08:00
2017-09-04 01:57:45 +08:00
import org.kamranzafar.jtar.TarInputStream;
2017-09-03 17:24:05 +08:00
import org.kamranzafar.jtar.TarOutputStream;
2017-08-31 03:07:33 +08:00
import java.io.BufferedInputStream;
2017-09-03 17:24:05 +08:00
import java.io.BufferedOutputStream;
2017-08-31 03:07:33 +08:00
import java.io.File;
2017-09-03 17:24:05 +08:00
import java.io.FileInputStream;
2017-08-31 03:07:33 +08:00
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
2017-12-07 04:20:15 +08:00
import java.util.ArrayList;
2017-08-31 03:07:33 +08:00
import java.util.Arrays;
import java.util.List;
2017-09-03 00:10:14 +08:00
public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
private static final int PATCH_MODE = 0;
private static final int DIRECT_MODE = 1;
2017-08-31 03:07:33 +08:00
private Uri mBootImg, mZip;
private List<String> console, logs;
2017-09-03 00:10:14 +08:00
private String mBootLocation;
private int mode;
2017-08-31 03:07:33 +08:00
private InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip) {
2017-08-31 03:07:33 +08:00
super(context);
this.console = console;
this.logs = logs;
2017-08-31 03:07:33 +08:00
mZip = zip;
2017-09-03 00:10:14 +08:00
}
public InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, Uri boot) {
this(context, console, logs, zip);
2017-09-03 00:10:14 +08:00
mBootImg = boot;
mode = PATCH_MODE;
}
public InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, String boot) {
this(context, console, logs, zip);
2017-09-03 00:10:14 +08:00
mBootLocation = boot;
mode = DIRECT_MODE;
2017-08-31 03:07:33 +08:00
}
@Override
protected Boolean doInBackground(Void... voids) {
2017-10-16 00:54:48 +08:00
MagiskManager mm = MagiskManager.get();
2017-08-31 03:07:33 +08:00
2017-10-20 00:41:44 +08:00
File install = new File(
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
mm.createDeviceProtectedStorageContext() :
mm).getFilesDir().getParent()
, "install");
2018-01-25 18:43:30 +08:00
Shell.Async.sh("rm -rf " + install);
2017-08-31 03:07:33 +08:00
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
String arch;
if (abis.contains("x86_64")) arch = "x64";
else if (abis.contains("arm64-v8a")) arch = "arm64";
else if (abis.contains("x86")) arch = "x86";
else arch = "arm";
console.add("- Device platform: " + arch);
2017-08-31 03:07:33 +08:00
try {
// Unzip files
console.add("- Extracting files");
2017-09-03 15:35:14 +08:00
try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
2017-08-31 03:07:33 +08:00
if (in == null) throw new FileNotFoundException();
BufferedInputStream buf = new BufferedInputStream(in);
buf.mark(Integer.MAX_VALUE);
2017-09-03 21:05:57 +08:00
ZipUtils.unzip(buf, install, arch + "/", true);
2017-08-31 03:07:33 +08:00
buf.reset();
2017-09-03 21:05:57 +08:00
ZipUtils.unzip(buf, install, "common/", true);
2017-08-31 03:07:33 +08:00
buf.reset();
2017-09-03 21:05:57 +08:00
ZipUtils.unzip(buf, install, "chromeos/", false);
2017-08-31 03:07:33 +08:00
buf.reset();
ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true);
2017-10-31 16:31:58 +08:00
buf.close();
2017-08-31 03:07:33 +08:00
} catch (FileNotFoundException e) {
console.add("! Invalid Uri");
2017-08-31 03:07:33 +08:00
throw e;
} catch (Exception e) {
console.add("! Cannot unzip zip");
2017-08-31 03:07:33 +08:00
throw e;
}
2018-01-25 18:43:30 +08:00
Shell.Sync.sh("chmod 755 " + install + "/*");
2017-08-31 03:07:33 +08:00
2017-10-31 16:31:58 +08:00
File boot = new File(install, "boot.img");
2017-12-07 04:20:15 +08:00
boolean highCompression = false;
2017-09-03 00:10:14 +08:00
switch (mode) {
case PATCH_MODE:
console.add("- Use boot image: " + boot);
2017-09-03 00:10:14 +08:00
// Copy boot image to local
try (
2017-09-26 20:46:58 +08:00
InputStream in = mm.getContentResolver().openInputStream(mBootImg);
OutputStream out = new FileOutputStream(boot)
2017-09-03 00:10:14 +08:00
) {
2017-09-04 01:57:45 +08:00
InputStream source;
2017-09-03 00:10:14 +08:00
if (in == null) throw new FileNotFoundException();
2017-09-04 01:57:45 +08:00
if (Utils.getNameFromUri(mm, mBootImg).endsWith(".tar")) {
// Extract boot.img from tar
TarInputStream tar = new TarInputStream(new BufferedInputStream(in));
org.kamranzafar.jtar.TarEntry entry;
while ((entry = tar.getNextEntry()) != null) {
if (entry.getName().equals("boot.img"))
break;
}
source = tar;
} else {
// Direct copy raw image
2017-09-26 20:46:58 +08:00
source = new BufferedInputStream(in);
2017-09-04 01:57:45 +08:00
}
2017-10-31 16:31:58 +08:00
Utils.inToOut(source, out);
2017-09-03 00:10:14 +08:00
} catch (FileNotFoundException e) {
console.add("! Invalid Uri");
2017-09-03 00:10:14 +08:00
throw e;
} catch (IOException e) {
console.add("! Copy failed");
2017-09-03 00:10:14 +08:00
throw e;
}
break;
case DIRECT_MODE:
console.add("- Use boot image: " + mBootLocation);
2017-12-07 04:20:15 +08:00
if (mm.remoteMagiskVersionCode >= 1463) {
List<String> ret = new ArrayList<>();
Shell.getShell().run(ret, logs,
install + "/magiskboot --parse " + mBootLocation,
"echo $?"
);
if (Utils.isValidShellResponse(ret)) {
highCompression = Integer.parseInt(ret.get(ret.size() - 1)) == 2;
if (highCompression)
console.add("! Insufficient boot partition size detected");
}
}
2017-11-03 02:25:42 +08:00
if (boot.createNewFile()) {
2018-01-25 18:43:30 +08:00
Shell.Sync.su("cat " + mBootLocation + " > " + boot);
2017-11-03 02:25:42 +08:00
} else {
console.add("! Dump boot image failed");
2017-11-03 02:25:42 +08:00
return false;
2017-10-31 16:31:58 +08:00
}
2017-09-03 00:10:14 +08:00
break;
default:
return false;
2017-08-31 03:07:33 +08:00
}
2017-10-31 16:31:58 +08:00
boolean isSigned;
try (InputStream in = new FileInputStream(boot)) {
isSigned = SignBoot.verifySignature(in, null);
if (isSigned) {
console.add("- Signed boot image detected");
2017-10-31 16:31:58 +08:00
}
} catch (Exception e) {
console.add("! Unable to check signature");
2017-10-31 16:31:58 +08:00
throw e;
}
2017-08-31 03:07:33 +08:00
2017-10-31 16:31:58 +08:00
// Force non-root shell
2017-09-05 04:07:33 +08:00
Shell shell;
2017-10-31 16:31:58 +08:00
if (Shell.rootAccess())
2018-01-25 18:43:30 +08:00
shell = Shell.newInstance("sh");
2017-10-31 16:31:58 +08:00
else
2017-10-15 23:02:44 +08:00
shell = Shell.getShell();
2017-08-31 03:07:33 +08:00
// Patch boot image
shell.run(console, logs,
2017-08-31 03:07:33 +08:00
"cd " + install,
Utils.fmt("KEEPFORCEENCRYPT=%b KEEPVERITY=%b HIGHCOMP=%b " +
"sh update-binary indep boot_patch.sh %s || echo 'Failed!'",
mm.keepEnc, mm.keepVerity, highCompression, boot));
2017-08-31 03:07:33 +08:00
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
2017-08-31 03:07:33 +08:00
return false;
2018-01-25 18:43:30 +08:00
shell.run(null, null, "mv -f new-boot.img ../",
2017-11-18 01:16:14 +08:00
"mv bin/busybox busybox",
"rm -rf bin *.img update-binary",
2017-11-04 04:01:58 +08:00
"cd /");
File patched_boot = new File(install.getParent(), "new-boot.img");
2017-10-31 16:31:58 +08:00
if (isSigned) {
console.add("- Signing boot image");
2017-11-04 04:01:58 +08:00
File signed = new File(install.getParent(), "signed.img");
2017-10-31 16:31:58 +08:00
AssetManager assets = mm.getAssets();
try (
2017-11-06 04:41:23 +08:00
InputStream in = new FileInputStream(patched_boot);
OutputStream out = new BufferedOutputStream(new FileOutputStream(signed));
InputStream keyIn = assets.open(Const.PRIVATE_KEY_NAME);
InputStream certIn = assets.open(Const.PUBLIC_KEY_NAME)
2017-10-31 16:31:58 +08:00
) {
SignBoot.doSignature("/boot", in, out, keyIn, certIn);
}
2018-01-25 18:43:30 +08:00
shell.run(null, null, "mv -f " + signed + " " + patched_boot);
2017-10-31 16:31:58 +08:00
}
2017-09-03 00:10:14 +08:00
switch (mode) {
case PATCH_MODE:
2017-11-21 00:34:25 +08:00
File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + mm.bootFormat);
2017-09-03 00:10:14 +08:00
dest.getParentFile().mkdirs();
2017-11-21 00:34:25 +08:00
OutputStream out;
2017-09-03 17:24:05 +08:00
switch (mm.bootFormat) {
case ".img.tar":
2017-11-21 00:34:25 +08:00
out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
((TarOutputStream) out).putNextEntry(new TarEntry(patched_boot, "boot.img"));
2017-09-03 17:24:05 +08:00
break;
2017-11-21 00:34:25 +08:00
default:
case ".img":
out = new BufferedOutputStream(new FileOutputStream(dest));
break;
}
try (InputStream in = new BufferedInputStream(new FileInputStream(patched_boot))) {
Utils.inToOut(in, out);
out.close();
2017-09-03 17:24:05 +08:00
}
console.add("");
console.add("*********************************");
console.add(" Patched Boot Image is placed in ");
console.add(" " + dest + " ");
console.add("*********************************");
2017-09-03 00:10:14 +08:00
break;
case DIRECT_MODE:
2017-12-16 02:01:04 +08:00
String binPath = mm.remoteMagiskVersionCode >= 1464 ? "/data/adb/magisk" : "/data/magisk";
Shell.getShell().run(console, logs,
2017-12-16 02:01:04 +08:00
Utils.fmt("rm -rf %s/*; mkdir -p %s; chmod 700 /data/adb", binPath, binPath),
2017-12-16 04:31:31 +08:00
Utils.fmt("cp -af %s/* %s; rm -rf %s", install, binPath, install),
2017-12-16 02:01:04 +08:00
Utils.fmt("flash_boot_image %s %s", patched_boot, mBootLocation),
2017-12-18 03:02:19 +08:00
mm.remoteMagiskVersionCode >= 1464 ? "[ -L /data/magisk.img ] || cp /data/magisk.img /data/adb/magisk.img" : "",
mm.keepVerity ? "" : "patch_dtbo_image");
2017-09-03 00:10:14 +08:00
break;
default:
return false;
}
2017-08-31 03:07:33 +08:00
2017-11-21 00:34:25 +08:00
patched_boot.delete();
console.add("- All done!");
2017-08-31 03:07:33 +08:00
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
FlashActivity activity = (FlashActivity) getActivity();
if (!result) {
console.add("! Installation failed");
activity.reboot.setVisibility(View.GONE);
}
activity.buttonPanel.setVisibility(View.VISIBLE);
2017-08-31 03:07:33 +08:00
}
}