Fix non-root boot patching

This commit is contained in:
topjohnwu 2018-06-25 19:46:41 +08:00
parent 4ff39f8817
commit 23f697d62b
2 changed files with 83 additions and 104 deletions

View File

@ -17,7 +17,6 @@ import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils; import com.topjohnwu.magisk.utils.ZipUtils;
import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.ShellUtils;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream; import com.topjohnwu.superuser.io.SuFileInputStream;
import com.topjohnwu.utils.SignBoot; import com.topjohnwu.utils.SignBoot;
@ -43,17 +42,18 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
private static final int DIRECT_MODE = 1; private static final int DIRECT_MODE = 1;
private static final int FIX_ENV_MODE = 2; private static final int FIX_ENV_MODE = 2;
private Uri mBootImg, mZip; private Uri bootUri, mZip;
private List<String> console, logs; private List<String> console, logs;
private String mBootLocation; private String mBoot;
private int mode; private int mode;
private File install; private File installDir;
private ProgressDialog dialog; private ProgressDialog dialog;
private boolean highCompression; private MagiskManager mm;
public InstallMagisk(Activity context, Uri zip) { public InstallMagisk(Activity context, Uri zip) {
super(context); super(context);
mZip = zip; mZip = zip;
mm = MagiskManager.get();
mode = FIX_ENV_MODE; mode = FIX_ENV_MODE;
} }
@ -65,14 +65,13 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri zip, Uri boot) { public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri zip, Uri boot) {
this(context, console, logs, zip); this(context, console, logs, zip);
mBootImg = boot; bootUri = boot;
highCompression = false;
mode = PATCH_MODE; mode = PATCH_MODE;
} }
public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri zip, String boot) { public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri zip, String boot) {
this(context, console, logs, zip); this(context, console, logs, zip);
mBootLocation = boot; mBoot = boot;
mode = DIRECT_MODE; mode = DIRECT_MODE;
} }
@ -86,19 +85,18 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
} }
private void extractFiles(String arch) throws IOException { private void extractFiles(String arch) throws IOException {
MagiskManager mm = MagiskManager.get();
console.add("- Extracting files"); console.add("- Extracting files");
try (InputStream in = mm.getContentResolver().openInputStream(mZip)) { try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
if (in == null) throw new FileNotFoundException(); if (in == null) throw new FileNotFoundException();
BufferedInputStream buf = new BufferedInputStream(in); BufferedInputStream buf = new BufferedInputStream(in);
buf.mark(Integer.MAX_VALUE); buf.mark(Integer.MAX_VALUE);
ZipUtils.unzip(buf, install, arch + "/", true); ZipUtils.unzip(buf, installDir, arch + "/", true);
buf.reset(); buf.reset();
ZipUtils.unzip(buf, install, "common/", true); ZipUtils.unzip(buf, installDir, "common/", true);
buf.reset(); buf.reset();
ZipUtils.unzip(buf, install, "chromeos/", false); ZipUtils.unzip(buf, installDir, "chromeos/", false);
buf.reset(); buf.reset();
ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true); ZipUtils.unzip(buf, installDir, "META-INF/com/google/android/update-binary", true);
buf.close(); buf.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
console.add("! Invalid Uri"); console.add("! Invalid Uri");
@ -108,21 +106,20 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
throw e; throw e;
} }
Shell.Sync.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk", Shell.Sync.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk",
install, install, install)); installDir, installDir, installDir));
} }
private boolean dumpBoot(File boot) throws IOException { private boolean dumpBoot() {
MagiskManager mm = MagiskManager.get(); console.add("- Copying boot image to " + mBoot);
switch (mode) {
case PATCH_MODE:
// Copy boot image to local // Copy boot image to local
try (InputStream in = mm.getContentResolver().openInputStream(mBootImg); try (InputStream in = mm.getContentResolver().openInputStream(bootUri);
OutputStream out = new FileOutputStream(boot) OutputStream out = new FileOutputStream(mBoot)
) { ) {
InputStream source; if (in == null)
if (in == null) throw new FileNotFoundException(); throw new FileNotFoundException();
if (Utils.getNameFromUri(mm, mBootImg).endsWith(".tar")) { InputStream src;
if (Utils.getNameFromUri(mm, bootUri).endsWith(".tar")) {
// Extract boot.img from tar // Extract boot.img from tar
TarInputStream tar = new TarInputStream(new BufferedInputStream(in)); TarInputStream tar = new TarInputStream(new BufferedInputStream(in));
org.kamranzafar.jtar.TarEntry entry; org.kamranzafar.jtar.TarEntry entry;
@ -130,46 +127,25 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
if (entry.getName().equals("boot.img")) if (entry.getName().equals("boot.img"))
break; break;
} }
source = tar; src = tar;
} else { } else {
// Direct copy raw image // Direct copy raw image
source = new BufferedInputStream(in); src = new BufferedInputStream(in);
} }
ShellUtils.pump(source, out); ShellUtils.pump(src, out);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
console.add("! Invalid Uri"); console.add("! Invalid Uri");
throw e; return false;
} catch (IOException e) { } catch (IOException e) {
console.add("! Copy failed"); console.add("! Copy failed");
throw e;
}
break;
case DIRECT_MODE:
console.add("- Patch boot/ramdisk image: " + mBootLocation);
if (mm.remoteMagiskVersionCode >= 1463) {
highCompression = Integer.parseInt(ShellUtils.fastCmd(Utils.fmt(
"%s/magiskboot --parse %s; echo $?", install, mBootLocation))) == 2;
if (highCompression)
console.add("! Insufficient boot partition size detected");
}
if (boot.createNewFile()) {
Shell.Sync.su("cat " + mBootLocation + " > " + boot);
} else {
console.add("! Dump boot image failed");
return false;
}
break;
default:
return false; return false;
} }
return true; return true;
} }
private boolean patchBoot(File boot, SuFile patched_boot) throws IOException { private File patchBoot() throws IOException {
MagiskManager mm = MagiskManager.get();
boolean isSigned; boolean isSigned;
try (InputStream in = new FileInputStream(boot)) { try (InputStream in = new SuFileInputStream(mBoot)) {
isSigned = SignBoot.verifySignature(in, null); isSigned = SignBoot.verifySignature(in, null);
if (isSigned) { if (isSigned) {
console.add("- Boot image is signed with AVB 1.0"); console.add("- Boot image is signed with AVB 1.0");
@ -181,35 +157,33 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
// Patch boot image // Patch boot image
Shell.Sync.sh(console, logs, Shell.Sync.sh(console, logs,
"cd " + install, "cd " + installDir,
Utils.fmt("KEEPFORCEENCRYPT=%b KEEPVERITY=%b HIGHCOMP=%b " + Utils.fmt("KEEPFORCEENCRYPT=%b KEEPVERITY=%b sh update-binary indep " +
"sh update-binary indep boot_patch.sh %s || echo 'Failed!'", "boot_patch.sh %s || echo 'Failed!'",
mm.keepEnc, mm.keepVerity, highCompression, boot)); mm.keepEnc, mm.keepVerity, mBoot));
if (TextUtils.equals(console.get(console.size() - 1), "Failed!")) if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return false; return null;
Shell.Sync.sh("mv -f new-boot.img ../", Shell.Sync.sh("mv bin/busybox busybox",
"mv bin/busybox busybox", "rm -rf magisk.apk bin boot.img update-binary",
"rm -rf magisk.apk bin *.img update-binary",
"cd /"); "cd /");
File patched = new File(installDir, "new-boot.img");
if (isSigned) { if (isSigned) {
console.add("- Signing boot image with test keys"); console.add("- Signing boot image with test keys");
File signed = new File(install.getParent(), "signed.img"); File signed = new File(installDir, "signed.img");
try (InputStream in = new SuFileInputStream(patched_boot); try (InputStream in = new BufferedInputStream(new FileInputStream(patched));
OutputStream out = new BufferedOutputStream(new FileOutputStream(signed)) OutputStream out = new BufferedOutputStream(new FileOutputStream(signed))
) { ) {
SignBoot.doSignature("/boot", in, out, null, null); SignBoot.doSignature("/boot", in, out, null, null);
} }
Shell.Sync.sh("mv -f " + signed + " " + patched_boot); signed.renameTo(patched);
} }
return true; return patched;
} }
private void outputBoot(SuFile patched_boot) throws IOException { private void outputBoot(File patched) throws IOException {
MagiskManager mm = MagiskManager.get();
switch (mode) { switch (mode) {
case PATCH_MODE: case PATCH_MODE:
File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + mm.bootFormat); File dest = new File(Const.EXTERNAL_PATH, "patched_boot" + mm.bootFormat);
@ -218,14 +192,14 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
switch (mm.bootFormat) { switch (mm.bootFormat) {
case ".img.tar": case ".img.tar":
out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest))); out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
((TarOutputStream) out).putNextEntry(new TarEntry(patched_boot, "boot.img")); ((TarOutputStream) out).putNextEntry(new TarEntry(patched, "boot.img"));
break; break;
default: default:
case ".img": case ".img":
out = new BufferedOutputStream(new FileOutputStream(dest)); out = new BufferedOutputStream(new FileOutputStream(dest));
break; break;
} }
try (InputStream in = new SuFileInputStream(patched_boot)) { try (InputStream in = new FileInputStream(patched)) {
ShellUtils.pump(in, out); ShellUtils.pump(in, out);
out.close(); out.close();
} }
@ -236,32 +210,37 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
console.add("*********************************"); console.add("*********************************");
break; break;
case DIRECT_MODE: case DIRECT_MODE:
String binPath = mm.remoteMagiskVersionCode >= Const.MAGISK_VER.HIDDEN_PATH ? "/data/adb/magisk" : "/data/magisk"; String binPath = mm.remoteMagiskVersionCode >= Const.MAGISK_VER.HIDDEN_PATH ?
"/data/adb/magisk" : "/data/magisk";
Shell.Sync.su(console, logs, Shell.Sync.su(console, logs,
Utils.fmt("flash_boot_image %s %s; rm -f %s", patched, mBoot, patched),
Utils.fmt("rm -rf %s/*; mkdir -p %s; chmod 700 /data/adb", binPath, binPath), Utils.fmt("rm -rf %s/*; mkdir -p %s; chmod 700 /data/adb", binPath, binPath),
Utils.fmt("cp -af %s/* %s; rm -rf %s", install, binPath, install), Utils.fmt("cp -af %s/* %s; rm -rf %s", installDir, binPath, installDir),
Utils.fmt("flash_boot_image %s %s", patched_boot, mBootLocation),
mm.keepVerity ? "" : "patch_dtbo_image"); mm.keepVerity ? "" : "patch_dtbo_image");
break; break;
} }
patched_boot.delete(); patched.delete();
} }
@Override @Override
protected Boolean doInBackground(Void... voids) { protected Boolean doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
if (mode == FIX_ENV_MODE) { if (mode == FIX_ENV_MODE) {
install = new File("/data/adb/magisk"); installDir = new File("/data/adb/magisk");
Shell.Sync.sh("rm -rf " + install + "/*"); Shell.Sync.sh("rm -rf " + installDir + "/*");
} else { } else {
install = new File( installDir = new File(
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
mm.createDeviceProtectedStorageContext() : mm) mm.createDeviceProtectedStorageContext() : mm)
.getFilesDir().getParent() .getFilesDir().getParent()
, "install"); , "install");
Shell.Sync.sh("rm -rf " + install); Shell.Sync.sh("rm -rf " + installDir);
install.mkdirs(); installDir.mkdirs();
}
if (mode == PATCH_MODE) {
mBoot = new File(installDir, "boot.img").getAbsolutePath();
if (!dumpBoot())
return false;
} }
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS); List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
@ -284,7 +263,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
extractFiles(arch); extractFiles(arch);
if (mode == FIX_ENV_MODE) { if (mode == FIX_ENV_MODE) {
Shell.Sync.sh( Shell.Sync.sh(
"cd " + install, "cd " + installDir,
"sh update-binary extract", "sh update-binary extract",
"rm -f update-binary magisk.apk", "rm -f update-binary magisk.apk",
"cd /", "cd /",
@ -292,13 +271,10 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
"/sbin/.core/mirror/bin/busybox --install -s /sbin/.core/busybox" "/sbin/.core/mirror/bin/busybox --install -s /sbin/.core/busybox"
); );
} else { } else {
File boot = new File(install, "boot.img"); File patched = patchBoot();
SuFile patched_boot = new SuFile(install.getParent(), "new-boot.img"); if (patched == null)
if (!dumpBoot(boot) || !patchBoot(boot, patched_boot))
return false; return false;
outputBoot(patched_boot); outputBoot(patched);
console.add("- All done!"); console.add("- All done!");
} }
} catch (Exception e) { } catch (Exception e) {
@ -317,7 +293,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
// Running in FlashActivity // Running in FlashActivity
FlashActivity activity = (FlashActivity) getActivity(); FlashActivity activity = (FlashActivity) getActivity();
if (!result) { if (!result) {
Shell.Async.sh("rm -rf " + install); Shell.Async.sh("rm -rf " + installDir);
console.add("! Installation failed"); console.add("! Installation failed");
activity.reboot.setVisibility(View.GONE); activity.reboot.setVisibility(View.GONE);
} }

View File

@ -40,8 +40,11 @@ public class ZipUtils {
} else { } else {
name = entry.getName(); name = entry.getName();
} }
SuFile dest = new SuFile(folder, name); File dest = new File(folder, name);
if (!dest.getParentFile().mkdirs()) {
dest = new SuFile(folder, name);
dest.getParentFile().mkdirs(); dest.getParentFile().mkdirs();
}
try (OutputStream out = new SuFileOutputStream(dest)) { try (OutputStream out = new SuFileOutputStream(dest)) {
ShellUtils.pump(zipfile, out); ShellUtils.pump(zipfile, out);
} }