mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 07:57:39 +00:00
Remove unused code and logic
This commit is contained in:
parent
af65d07456
commit
f33343b4e6
@ -20,13 +20,11 @@ import com.topjohnwu.magisk.core.isRunningAsStub
|
|||||||
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||||
import com.topjohnwu.magisk.core.ktx.reboot
|
import com.topjohnwu.magisk.core.ktx.reboot
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.ktx.withStreams
|
|
||||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.inputStream
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.core.utils.RootUtils
|
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||||
import com.topjohnwu.magisk.signing.SignBoot
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.topjohnwu.superuser.ShellUtils
|
import com.topjohnwu.superuser.ShellUtils
|
||||||
import com.topjohnwu.superuser.internal.NOPList
|
import com.topjohnwu.superuser.internal.NOPList
|
||||||
@ -481,22 +479,6 @@ abstract class MagiskInstallImpl protected constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun patchBoot(): Boolean {
|
private fun patchBoot(): Boolean {
|
||||||
var isSigned = false
|
|
||||||
if (!srcBoot.isCharacter) {
|
|
||||||
try {
|
|
||||||
srcBoot.newInputStream().use {
|
|
||||||
if (SignBoot.verifySignature(it, null)) {
|
|
||||||
isSigned = true
|
|
||||||
console.add("- Boot image is signed with AVB 1.0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
console.add("! Unable to check signature")
|
|
||||||
Timber.e(e)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val newBoot = installDir.getChildFile("new-boot.img")
|
val newBoot = installDir.getChildFile("new-boot.img")
|
||||||
if (!useRootDir) {
|
if (!useRootDir) {
|
||||||
// Create output files before hand
|
// Create output files before hand
|
||||||
@ -511,31 +493,11 @@ abstract class MagiskInstallImpl protected constructor(
|
|||||||
"PATCHVBMETAFLAG=${Config.patchVbmeta} " +
|
"PATCHVBMETAFLAG=${Config.patchVbmeta} " +
|
||||||
"RECOVERYMODE=${Config.recovery} " +
|
"RECOVERYMODE=${Config.recovery} " +
|
||||||
"SYSTEM_ROOT=${Info.isSAR} " +
|
"SYSTEM_ROOT=${Info.isSAR} " +
|
||||||
"sh boot_patch.sh $srcBoot")
|
"sh boot_patch.sh $srcBoot",
|
||||||
|
"./magiskboot cleanup",
|
||||||
|
"cd /")
|
||||||
|
|
||||||
if (!cmds.sh().isSuccess)
|
return cmds.sh().isSuccess
|
||||||
return false
|
|
||||||
|
|
||||||
val job = shell.newJob().add("./magiskboot cleanup", "cd /")
|
|
||||||
|
|
||||||
if (isSigned) {
|
|
||||||
console.add("- Signing boot image with verity keys")
|
|
||||||
val signed = File.createTempFile("signed", ".img", context.cacheDir)
|
|
||||||
try {
|
|
||||||
val src = newBoot.newInputStream().buffered()
|
|
||||||
val out = signed.outputStream().buffered()
|
|
||||||
withStreams(src, out) { _, _ ->
|
|
||||||
SignBoot.doSignature(null, null, src, out, "/boot")
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
console.add("! Unable to sign image")
|
|
||||||
Timber.e(e)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
job.add("cat $signed > $newBoot", "rm -f $signed")
|
|
||||||
}
|
|
||||||
job.exec()
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flashBoot() = "direct_install $installDir $srcBoot".sh().isSuccess
|
private fun flashBoot() = "direct_install $installDir $srcBoot".sh().isSuccess
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.signing;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1InputStream;
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
||||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
|
||||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
|
||||||
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.Key;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.security.spec.ECPrivateKeySpec;
|
|
||||||
import java.security.spec.ECPublicKeySpec;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class CryptoUtils {
|
|
||||||
|
|
||||||
static final Map<String, String> ID_TO_ALG;
|
|
||||||
static final Map<String, String> ALG_TO_ID;
|
|
||||||
|
|
||||||
static {
|
|
||||||
ID_TO_ALG = new HashMap<>();
|
|
||||||
ALG_TO_ID = new HashMap<>();
|
|
||||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA256.getId(), "SHA256withECDSA");
|
|
||||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA384.getId(), "SHA384withECDSA");
|
|
||||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA512.getId(), "SHA512withECDSA");
|
|
||||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1withRSA");
|
|
||||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256withRSA");
|
|
||||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512withRSA");
|
|
||||||
ALG_TO_ID.put("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256.getId());
|
|
||||||
ALG_TO_ID.put("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384.getId());
|
|
||||||
ALG_TO_ID.put("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512.getId());
|
|
||||||
ALG_TO_ID.put("SHA1withRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
|
|
||||||
ALG_TO_ID.put("SHA256withRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption.getId());
|
|
||||||
ALG_TO_ID.put("SHA512withRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getSignatureAlgorithm(Key key) throws Exception {
|
|
||||||
if ("EC".equals(key.getAlgorithm())) {
|
|
||||||
int curveSize;
|
|
||||||
KeyFactory factory = KeyFactory.getInstance("EC");
|
|
||||||
if (key instanceof PublicKey) {
|
|
||||||
ECPublicKeySpec spec = factory.getKeySpec(key, ECPublicKeySpec.class);
|
|
||||||
curveSize = spec.getParams().getCurve().getField().getFieldSize();
|
|
||||||
} else if (key instanceof PrivateKey) {
|
|
||||||
ECPrivateKeySpec spec = factory.getKeySpec(key, ECPrivateKeySpec.class);
|
|
||||||
curveSize = spec.getParams().getCurve().getField().getFieldSize();
|
|
||||||
} else {
|
|
||||||
throw new InvalidKeySpecException();
|
|
||||||
}
|
|
||||||
if (curveSize <= 256) {
|
|
||||||
return "SHA256withECDSA";
|
|
||||||
} else if (curveSize <= 384) {
|
|
||||||
return "SHA384withECDSA";
|
|
||||||
} else {
|
|
||||||
return "SHA512withECDSA";
|
|
||||||
}
|
|
||||||
} else if ("RSA".equals(key.getAlgorithm())) {
|
|
||||||
return "SHA256withRSA";
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static AlgorithmIdentifier getSignatureAlgorithmIdentifier(Key key) throws Exception {
|
|
||||||
String id = ALG_TO_ID.get(getSignatureAlgorithm(key));
|
|
||||||
if (id == null) {
|
|
||||||
throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
|
|
||||||
}
|
|
||||||
return new AlgorithmIdentifier(new ASN1ObjectIdentifier(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static X509Certificate readCertificate(InputStream input)
|
|
||||||
throws IOException, GeneralSecurityException {
|
|
||||||
try {
|
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
||||||
return (X509Certificate) cf.generateCertificate(input);
|
|
||||||
} finally {
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a PKCS#8 format private key. */
|
|
||||||
public static PrivateKey readPrivateKey(InputStream input)
|
|
||||||
throws IOException, GeneralSecurityException {
|
|
||||||
try {
|
|
||||||
ByteArrayStream buf = new ByteArrayStream();
|
|
||||||
buf.readFrom(input);
|
|
||||||
byte[] bytes = buf.toByteArray();
|
|
||||||
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
|
|
||||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
|
|
||||||
/*
|
|
||||||
* Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
|
|
||||||
* OID and use that to construct a KeyFactory.
|
|
||||||
*/
|
|
||||||
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
|
|
||||||
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
|
|
||||||
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
|
|
||||||
return KeyFactory.getInstance(algOid).generatePrivate(spec);
|
|
||||||
} finally {
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,382 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.signing;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1Encodable;
|
|
||||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
|
||||||
import org.bouncycastle.asn1.ASN1InputStream;
|
|
||||||
import org.bouncycastle.asn1.ASN1Integer;
|
|
||||||
import org.bouncycastle.asn1.ASN1Object;
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
||||||
import org.bouncycastle.asn1.ASN1Primitive;
|
|
||||||
import org.bouncycastle.asn1.ASN1Sequence;
|
|
||||||
import org.bouncycastle.asn1.DEROctetString;
|
|
||||||
import org.bouncycastle.asn1.DERPrintableString;
|
|
||||||
import org.bouncycastle.asn1.DERSequence;
|
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FilterInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class SignBoot {
|
|
||||||
|
|
||||||
private static final int BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET = 1632;
|
|
||||||
private static final int BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET = 1648;
|
|
||||||
|
|
||||||
// Arbitrary maximum header version value; when greater assume the field is dt/extra size
|
|
||||||
private static final int BOOT_IMAGE_HEADER_VERSION_MAXIMUM = 8;
|
|
||||||
|
|
||||||
// Maximum header size byte value to read (currently the bootimg minimum page size)
|
|
||||||
private static final int BOOT_IMAGE_HEADER_SIZE_MAXIMUM = 2048;
|
|
||||||
|
|
||||||
private static class PushBackRWStream extends FilterInputStream {
|
|
||||||
private OutputStream out;
|
|
||||||
private int pos = 0;
|
|
||||||
private byte[] backBuf;
|
|
||||||
|
|
||||||
PushBackRWStream(InputStream in, OutputStream o) {
|
|
||||||
super(in);
|
|
||||||
out = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException {
|
|
||||||
int b;
|
|
||||||
if (backBuf != null && backBuf.length > pos) {
|
|
||||||
b = backBuf[pos++];
|
|
||||||
} else {
|
|
||||||
b = super.read();
|
|
||||||
out.write(b);
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] bytes, int off, int len) throws IOException {
|
|
||||||
int read = 0;
|
|
||||||
if (backBuf != null && backBuf.length > pos) {
|
|
||||||
read = Math.min(len, backBuf.length - pos);
|
|
||||||
System.arraycopy(backBuf, pos, bytes, off, read);
|
|
||||||
pos += read;
|
|
||||||
off += read;
|
|
||||||
len -= read;
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
int ar = super.read(bytes, off, len);
|
|
||||||
read += ar;
|
|
||||||
out.write(bytes, off, ar);
|
|
||||||
}
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unread(byte[] buf) {
|
|
||||||
backBuf = buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int fullRead(InputStream in, byte[] b) throws IOException {
|
|
||||||
return fullRead(in, b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int fullRead(InputStream in, byte[] b, int off, int len) throws IOException {
|
|
||||||
int n = 0;
|
|
||||||
while (n < len) {
|
|
||||||
int count = in.read(b, off + n, len - n);
|
|
||||||
if (count <= 0)
|
|
||||||
break;
|
|
||||||
n += count;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean doSignature(
|
|
||||||
@Nullable X509Certificate cert, @Nullable PrivateKey key,
|
|
||||||
@NonNull InputStream imgIn, @NonNull OutputStream imgOut, @NonNull String target
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
PushBackRWStream in = new PushBackRWStream(imgIn, imgOut);
|
|
||||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
|
||||||
// First read the header
|
|
||||||
fullRead(in, hdr);
|
|
||||||
int signableSize = getSignableImageSize(hdr);
|
|
||||||
// Unread header
|
|
||||||
in.unread(hdr);
|
|
||||||
BootSignature bootsig = new BootSignature(target, signableSize);
|
|
||||||
if (cert == null) {
|
|
||||||
cert = CryptoUtils.readCertificate(
|
|
||||||
new ByteArrayInputStream(KeyData.verityCert()));
|
|
||||||
}
|
|
||||||
bootsig.setCertificate(cert);
|
|
||||||
if (key == null) {
|
|
||||||
key = CryptoUtils.readPrivateKey(
|
|
||||||
new ByteArrayInputStream(KeyData.verityKey()));
|
|
||||||
}
|
|
||||||
byte[] sig = bootsig.sign(key, in, signableSize);
|
|
||||||
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(key));
|
|
||||||
byte[] encoded_bootsig = bootsig.getEncoded();
|
|
||||||
imgOut.write(encoded_bootsig);
|
|
||||||
imgOut.flush();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean verifySignature(InputStream imgIn, X509Certificate cert) {
|
|
||||||
try {
|
|
||||||
// Read the header for size
|
|
||||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
|
||||||
if (fullRead(imgIn, hdr) != hdr.length) {
|
|
||||||
System.err.println("Unable to read image header");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int signableSize = getSignableImageSize(hdr);
|
|
||||||
|
|
||||||
// Read the rest of the image
|
|
||||||
byte[] rawImg = Arrays.copyOf(hdr, signableSize);
|
|
||||||
int remain = signableSize - hdr.length;
|
|
||||||
if (fullRead(imgIn, rawImg, hdr.length, remain) != remain) {
|
|
||||||
System.err.println("Unable to read image");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read footer, which contains the signature
|
|
||||||
byte[] signature = new byte[4096];
|
|
||||||
if (imgIn.read(signature) == -1 || Arrays.equals(signature, new byte [signature.length])) {
|
|
||||||
System.err.println("Invalid image: not signed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BootSignature bootsig = new BootSignature(signature);
|
|
||||||
if (cert != null) {
|
|
||||||
bootsig.setCertificate(cert);
|
|
||||||
}
|
|
||||||
if (bootsig.verify(rawImg, signableSize)) {
|
|
||||||
System.err.println("Signature is VALID");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
System.err.println("Signature is INVALID");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getSignableImageSize(byte[] data) throws Exception {
|
|
||||||
if (!Arrays.equals(Arrays.copyOfRange(data, 0, 8),
|
|
||||||
"ANDROID!".getBytes("US-ASCII"))) {
|
|
||||||
throw new IllegalArgumentException("Invalid image header: missing magic");
|
|
||||||
}
|
|
||||||
ByteBuffer image = ByteBuffer.wrap(data);
|
|
||||||
image.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
image.getLong(); // magic
|
|
||||||
int kernelSize = image.getInt();
|
|
||||||
image.getInt(); // kernel_addr
|
|
||||||
int ramdskSize = image.getInt();
|
|
||||||
image.getInt(); // ramdisk_addr
|
|
||||||
int secondSize = image.getInt();
|
|
||||||
image.getLong(); // second_addr + tags_addr
|
|
||||||
int pageSize = image.getInt();
|
|
||||||
if (pageSize >= 0x02000000) {
|
|
||||||
throw new IllegalArgumentException("Invalid image header: PXA header detected");
|
|
||||||
}
|
|
||||||
int length = pageSize // include the page aligned image header
|
|
||||||
+ ((kernelSize + pageSize - 1) / pageSize) * pageSize
|
|
||||||
+ ((ramdskSize + pageSize - 1) / pageSize) * pageSize
|
|
||||||
+ ((secondSize + pageSize - 1) / pageSize) * pageSize;
|
|
||||||
int headerVersion = image.getInt(); // boot image header version or dt/extra size
|
|
||||||
if (headerVersion > 0 && headerVersion < BOOT_IMAGE_HEADER_VERSION_MAXIMUM) {
|
|
||||||
image.position(BOOT_IMAGE_HEADER_V1_RECOVERY_DTBO_SIZE_OFFSET);
|
|
||||||
int recoveryDtboLength = image.getInt();
|
|
||||||
length += ((recoveryDtboLength + pageSize - 1) / pageSize) * pageSize;
|
|
||||||
image.getLong(); // recovery_dtbo address
|
|
||||||
int headerSize = image.getInt();
|
|
||||||
if (headerVersion == 2) {
|
|
||||||
image.position(BOOT_IMAGE_HEADER_V2_DTB_SIZE_OFFSET);
|
|
||||||
int dtbLength = image.getInt();
|
|
||||||
length += ((dtbLength + pageSize - 1) / pageSize) * pageSize;
|
|
||||||
image.getLong(); // dtb address
|
|
||||||
}
|
|
||||||
if (image.position() != headerSize) {
|
|
||||||
throw new IllegalArgumentException("Invalid image header: invalid header length");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// headerVersion is 0 or actually dt/extra size in this case
|
|
||||||
length += ((headerVersion + pageSize - 1) / pageSize) * pageSize;
|
|
||||||
}
|
|
||||||
length = ((length + pageSize - 1) / pageSize) * pageSize;
|
|
||||||
if (length <= 0) {
|
|
||||||
throw new IllegalArgumentException("Invalid image header: invalid length");
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class BootSignature extends ASN1Object {
|
|
||||||
private ASN1Integer formatVersion;
|
|
||||||
private ASN1Encodable certificate;
|
|
||||||
private AlgorithmIdentifier algId;
|
|
||||||
private DERPrintableString target;
|
|
||||||
private ASN1Integer length;
|
|
||||||
private DEROctetString signature;
|
|
||||||
private PublicKey publicKey;
|
|
||||||
private static final int FORMAT_VERSION = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the object for signing an image file
|
|
||||||
* @param target Target name, included in the signed data
|
|
||||||
* @param length Length of the image, included in the signed data
|
|
||||||
*/
|
|
||||||
public BootSignature(String target, int length) {
|
|
||||||
this.formatVersion = new ASN1Integer(FORMAT_VERSION);
|
|
||||||
this.target = new DERPrintableString(target);
|
|
||||||
this.length = new ASN1Integer(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the object for verifying a signed image file
|
|
||||||
* @param signature Signature footer
|
|
||||||
*/
|
|
||||||
public BootSignature(byte[] signature) throws Exception {
|
|
||||||
ASN1InputStream stream = new ASN1InputStream(signature);
|
|
||||||
ASN1Sequence sequence = (ASN1Sequence) stream.readObject();
|
|
||||||
formatVersion = (ASN1Integer) sequence.getObjectAt(0);
|
|
||||||
if (formatVersion.getValue().intValue() != FORMAT_VERSION) {
|
|
||||||
throw new IllegalArgumentException("Unsupported format version");
|
|
||||||
}
|
|
||||||
certificate = sequence.getObjectAt(1);
|
|
||||||
byte[] encoded = ((ASN1Object) certificate).getEncoded();
|
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
|
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
||||||
X509Certificate c = (X509Certificate) cf.generateCertificate(bis);
|
|
||||||
publicKey = c.getPublicKey();
|
|
||||||
ASN1Sequence algId = (ASN1Sequence) sequence.getObjectAt(2);
|
|
||||||
this.algId = new AlgorithmIdentifier((ASN1ObjectIdentifier) algId.getObjectAt(0));
|
|
||||||
ASN1Sequence attrs = (ASN1Sequence) sequence.getObjectAt(3);
|
|
||||||
target = (DERPrintableString) attrs.getObjectAt(0);
|
|
||||||
length = (ASN1Integer) attrs.getObjectAt(1);
|
|
||||||
this.signature = (DEROctetString) sequence.getObjectAt(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ASN1Object getAuthenticatedAttributes() {
|
|
||||||
ASN1EncodableVector attrs = new ASN1EncodableVector();
|
|
||||||
attrs.add(target);
|
|
||||||
attrs.add(length);
|
|
||||||
return new DERSequence(attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getEncodedAuthenticatedAttributes() throws IOException {
|
|
||||||
return getAuthenticatedAttributes().getEncoded();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSignature(byte[] sig, AlgorithmIdentifier algId) {
|
|
||||||
this.algId = algId;
|
|
||||||
signature = new DEROctetString(sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCertificate(X509Certificate cert)
|
|
||||||
throws CertificateEncodingException, IOException {
|
|
||||||
ASN1InputStream s = new ASN1InputStream(cert.getEncoded());
|
|
||||||
certificate = s.readObject();
|
|
||||||
publicKey = cert.getPublicKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] sign(PrivateKey key, InputStream is, int len) throws Exception {
|
|
||||||
Signature signer = Signature.getInstance(CryptoUtils.getSignatureAlgorithm(key));
|
|
||||||
signer.initSign(key);
|
|
||||||
int read;
|
|
||||||
byte buffer[] = new byte[4096];
|
|
||||||
while ((read = is.read(buffer, 0, Math.min(len, buffer.length))) > 0) {
|
|
||||||
signer.update(buffer, 0, read);
|
|
||||||
len -= read;
|
|
||||||
}
|
|
||||||
signer.update(getEncodedAuthenticatedAttributes());
|
|
||||||
return signer.sign();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean verify(byte[] image, int length) throws Exception {
|
|
||||||
if (this.length.getValue().intValue() != length) {
|
|
||||||
throw new IllegalArgumentException("Invalid image length");
|
|
||||||
}
|
|
||||||
String algName = CryptoUtils.ID_TO_ALG.get(algId.getAlgorithm().getId());
|
|
||||||
if (algName == null) {
|
|
||||||
throw new IllegalArgumentException("Unsupported algorithm " + algId.getAlgorithm());
|
|
||||||
}
|
|
||||||
Signature verifier = Signature.getInstance(algName);
|
|
||||||
verifier.initVerify(publicKey);
|
|
||||||
verifier.update(image, 0, length);
|
|
||||||
verifier.update(getEncodedAuthenticatedAttributes());
|
|
||||||
return verifier.verify(signature.getOctets());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ASN1Primitive toASN1Primitive() {
|
|
||||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
|
||||||
v.add(formatVersion);
|
|
||||||
v.add(certificate);
|
|
||||||
v.add(algId);
|
|
||||||
v.add(getAuthenticatedAttributes());
|
|
||||||
v.add(signature);
|
|
||||||
return new DERSequence(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args.length > 0 && "-verify".equals(args[0])) {
|
|
||||||
X509Certificate cert = null;
|
|
||||||
if (args.length >= 2) {
|
|
||||||
// args[1] is the path to a public key certificate
|
|
||||||
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
|
|
||||||
}
|
|
||||||
boolean signed = SignBoot.verifySignature(System.in, cert);
|
|
||||||
System.exit(signed ? 0 : 1);
|
|
||||||
} else if (args.length > 0 && "-sign".equals(args[0])) {
|
|
||||||
X509Certificate cert = null;
|
|
||||||
PrivateKey key = null;
|
|
||||||
String name = "/boot";
|
|
||||||
|
|
||||||
if (args.length >= 3) {
|
|
||||||
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
|
|
||||||
key = CryptoUtils.readPrivateKey(new FileInputStream(args[2]));
|
|
||||||
}
|
|
||||||
if (args.length == 2) {
|
|
||||||
name = args[1];
|
|
||||||
} else if (args.length >= 4) {
|
|
||||||
name = args[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean result = SignBoot.doSignature(cert, key, System.in, System.out, name);
|
|
||||||
System.exit(result ? 0 : 1);
|
|
||||||
} else {
|
|
||||||
System.err.println(
|
|
||||||
"BootSigner <actions> [args]\n" +
|
|
||||||
"Input from stdin, output to stdout\n" +
|
|
||||||
"\n" +
|
|
||||||
"Actions:\n" +
|
|
||||||
" -verify [x509.pem]\n" +
|
|
||||||
" verify image. cert is optional.\n" +
|
|
||||||
" -sign [x509.pem] [pk8] [name]\n" +
|
|
||||||
" sign image. name and the cert/key pair are optional.\n" +
|
|
||||||
" name should be either /boot (default) or /recovery.\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -64,19 +64,6 @@ private fun PrintStream.byteField(name: String, bytes: ByteArray) {
|
|||||||
println("}")
|
println("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun genKeyData(keysDir: File, outSrc: File) {
|
|
||||||
outSrc.parentFile.mkdirs()
|
|
||||||
PrintStream(outSrc).use {
|
|
||||||
it.println("package com.topjohnwu.magisk.signing;")
|
|
||||||
it.println("public final class KeyData {")
|
|
||||||
|
|
||||||
it.byteField("verityCert", File(keysDir, "verity.x509.pem").readBytes())
|
|
||||||
it.byteField("verityKey", File(keysDir, "verity.pk8").readBytes())
|
|
||||||
|
|
||||||
it.println("}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CacheableTask
|
@CacheableTask
|
||||||
abstract class ManifestUpdater: DefaultTask() {
|
abstract class ManifestUpdater: DefaultTask() {
|
||||||
@get:Input
|
@get:Input
|
||||||
|
@ -305,19 +305,6 @@ fun Project.setupApp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mergeAssetsProvider.configure { dependsOn(syncAssets) }
|
mergeAssetsProvider.configure { dependsOn(syncAssets) }
|
||||||
|
|
||||||
val keysDir = rootProject.file("tools/keys")
|
|
||||||
val outSrcDir = File(buildDir, "generated/source/keydata/$name")
|
|
||||||
val outSrc = File(outSrcDir, "com/topjohnwu/magisk/signing/KeyData.java")
|
|
||||||
|
|
||||||
val genSrcTask = tasks.register("generate${variantCapped}KeyData") {
|
|
||||||
inputs.dir(keysDir)
|
|
||||||
outputs.file(outSrc)
|
|
||||||
doLast {
|
|
||||||
genKeyData(keysDir, outSrc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
registerJavaGeneratingTask(genSrcTask, outSrcDir)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,6 @@ main() {
|
|||||||
ui_print "- Device platform: $ABI"
|
ui_print "- Device platform: $ABI"
|
||||||
|
|
||||||
remove_system_su
|
remove_system_su
|
||||||
find_magisk_apk
|
|
||||||
install_magisk
|
install_magisk
|
||||||
|
|
||||||
# Cleanups
|
# Cleanups
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
umask 022
|
umask 022
|
||||||
|
|
||||||
OUTFD=$2
|
OUTFD=$2
|
||||||
APK="$3"
|
|
||||||
COMMONDIR=$INSTALLER/assets
|
COMMONDIR=$INSTALLER/assets
|
||||||
CHROMEDIR=$INSTALLER/assets/chromeos
|
CHROMEDIR=$INSTALLER/assets/chromeos
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
umask 022
|
umask 022
|
||||||
|
|
||||||
OUTFD=$2
|
OUTFD=$2
|
||||||
APK="$3"
|
|
||||||
COMMONDIR=$INSTALLER/assets
|
COMMONDIR=$INSTALLER/assets
|
||||||
CHROMEDIR=$INSTALLER/assets/chromeos
|
CHROMEDIR=$INSTALLER/assets/chromeos
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ recovery_actions() {
|
|||||||
recovery_cleanup() {
|
recovery_cleanup() {
|
||||||
local DIR
|
local DIR
|
||||||
ui_print "- Unmounting partitions"
|
ui_print "- Unmounting partitions"
|
||||||
(umount_apex
|
(
|
||||||
if [ ! -d /postinstall/tmp ]; then
|
if [ ! -d /postinstall/tmp ]; then
|
||||||
umount -l /system
|
umount -l /system
|
||||||
umount -l /system_root
|
umount -l /system_root
|
||||||
@ -199,7 +199,8 @@ recovery_cleanup() {
|
|||||||
mv -f ${DIR}_link $DIR
|
mv -f ${DIR}_link $DIR
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
umount -l /dev/random) 2>/dev/null
|
umount -l /dev/random
|
||||||
|
) 2>/dev/null
|
||||||
[ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB
|
[ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB
|
||||||
[ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE
|
[ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE
|
||||||
[ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG
|
[ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG
|
||||||
@ -306,92 +307,7 @@ mount_partitions() {
|
|||||||
SYSTEM_ROOT=false
|
SYSTEM_ROOT=false
|
||||||
grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts && SYSTEM_ROOT=true
|
grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts && SYSTEM_ROOT=true
|
||||||
fi
|
fi
|
||||||
# /vendor is used only on some older devices for recovery AVBv1 signing so is not critical if fails
|
|
||||||
[ -L /system/vendor ] && mount_name vendor$SLOT /vendor '-o ro'
|
|
||||||
$SYSTEM_ROOT && ui_print "- Device is system-as-root"
|
$SYSTEM_ROOT && ui_print "- Device is system-as-root"
|
||||||
|
|
||||||
# Allow /system/bin commands (dalvikvm) on Android 10+ in recovery
|
|
||||||
$BOOTMODE || mount_apex
|
|
||||||
}
|
|
||||||
|
|
||||||
# loop_setup <ext4_img>, sets LOOPDEV
|
|
||||||
loop_setup() {
|
|
||||||
unset LOOPDEV
|
|
||||||
local LOOP
|
|
||||||
local MINORX=1
|
|
||||||
[ -e /dev/block/loop1 ] && MINORX=$(stat -Lc '%T' /dev/block/loop1)
|
|
||||||
local NUM=0
|
|
||||||
while [ $NUM -lt 64 ]; do
|
|
||||||
LOOP=/dev/block/loop$NUM
|
|
||||||
[ -e $LOOP ] || mknod $LOOP b 7 $((NUM * MINORX))
|
|
||||||
if losetup $LOOP "$1" 2>/dev/null; then
|
|
||||||
LOOPDEV=$LOOP
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
NUM=$((NUM + 1))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
mount_apex() {
|
|
||||||
$BOOTMODE || [ ! -d /system/apex ] && return
|
|
||||||
local APEX DEST
|
|
||||||
setup_mntpoint /apex
|
|
||||||
mount -t tmpfs tmpfs /apex -o mode=755
|
|
||||||
local PATTERN='s/.*"name":[^"]*"\([^"]*\).*/\1/p'
|
|
||||||
for APEX in /system/apex/*; do
|
|
||||||
if [ -f $APEX ]; then
|
|
||||||
# handle CAPEX APKs, extract actual APEX APK first
|
|
||||||
unzip -qo $APEX original_apex -d /apex
|
|
||||||
[ -f /apex/original_apex ] && APEX=/apex/original_apex # unzip doesn't do return codes
|
|
||||||
# APEX APKs, extract and loop mount
|
|
||||||
unzip -qo $APEX apex_payload.img -d /apex
|
|
||||||
DEST=$(unzip -qp $APEX apex_manifest.pb | strings | head -n 1 | tr -dc '[:alnum:].-_\n')
|
|
||||||
[ -z $DEST ] && DEST=$(unzip -qp $APEX apex_manifest.json | sed -n $PATTERN)
|
|
||||||
[ -z $DEST ] && continue
|
|
||||||
DEST=/apex/$DEST
|
|
||||||
mkdir -p $DEST
|
|
||||||
loop_setup /apex/apex_payload.img
|
|
||||||
if [ ! -z $LOOPDEV ]; then
|
|
||||||
ui_print "- Mounting $DEST"
|
|
||||||
mount -t ext4 -o ro,noatime $LOOPDEV $DEST
|
|
||||||
fi
|
|
||||||
rm -f /apex/original_apex /apex/apex_payload.img
|
|
||||||
elif [ -d $APEX ]; then
|
|
||||||
# APEX folders, bind mount directory
|
|
||||||
if [ -f $APEX/apex_manifest.json ]; then
|
|
||||||
DEST=/apex/$(sed -n $PATTERN $APEX/apex_manifest.json)
|
|
||||||
elif [ -f $APEX/apex_manifest.pb ]; then
|
|
||||||
DEST=/apex/$(strings $APEX/apex_manifest.pb | head -n 1 | tr -dc '[:alnum:].-_\n')
|
|
||||||
else
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
mkdir -p $DEST
|
|
||||||
ui_print "- Mounting $DEST"
|
|
||||||
mount -o bind $APEX $DEST
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
export ANDROID_RUNTIME_ROOT=/apex/com.android.runtime
|
|
||||||
export ANDROID_TZDATA_ROOT=/apex/com.android.tzdata
|
|
||||||
export ANDROID_ART_ROOT=/apex/com.android.art
|
|
||||||
export ANDROID_I18N_ROOT=/apex/com.android.i18n
|
|
||||||
local APEXJARS=$(find /apex -name '*.jar' | sort | tr '\n' ':')
|
|
||||||
local FWK=/system/framework
|
|
||||||
export BOOTCLASSPATH=${APEXJARS}\
|
|
||||||
$FWK/framework.jar:$FWK/ext.jar:$FWK/telephony-common.jar:\
|
|
||||||
$FWK/voip-common.jar:$FWK/ims-common.jar:$FWK/telephony-ext.jar
|
|
||||||
}
|
|
||||||
|
|
||||||
umount_apex() {
|
|
||||||
[ -d /apex ] || return
|
|
||||||
umount -l /apex
|
|
||||||
for loop in /dev/block/loop*; do
|
|
||||||
losetup -d $loop 2>/dev/null
|
|
||||||
done
|
|
||||||
unset ANDROID_RUNTIME_ROOT
|
|
||||||
unset ANDROID_TZDATA_ROOT
|
|
||||||
unset ANDROID_ART_ROOT
|
|
||||||
unset ANDROID_I18N_ROOT
|
|
||||||
unset BOOTCLASSPATH
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# After calling this method, the following variables will be set:
|
# After calling this method, the following variables will be set:
|
||||||
@ -452,16 +368,11 @@ find_boot_image() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
flash_image() {
|
flash_image() {
|
||||||
|
local CMD1
|
||||||
case "$1" in
|
case "$1" in
|
||||||
*.gz) CMD1="gzip -d < '$1' 2>/dev/null";;
|
*.gz) CMD1="gzip -d < '$1' 2>/dev/null";;
|
||||||
*) CMD1="cat '$1'";;
|
*) CMD1="cat '$1'";;
|
||||||
esac
|
esac
|
||||||
if $BOOTSIGNED; then
|
|
||||||
CMD2="$BOOTSIGNER -sign"
|
|
||||||
ui_print "- Sign image with verity keys"
|
|
||||||
else
|
|
||||||
CMD2="cat -"
|
|
||||||
fi
|
|
||||||
if [ -b "$2" ]; then
|
if [ -b "$2" ]; then
|
||||||
local img_sz=$(stat -c '%s' "$1")
|
local img_sz=$(stat -c '%s' "$1")
|
||||||
local blk_sz=$(blockdev --getsize64 "$2")
|
local blk_sz=$(blockdev --getsize64 "$2")
|
||||||
@ -469,13 +380,13 @@ flash_image() {
|
|||||||
blockdev --setrw "$2"
|
blockdev --setrw "$2"
|
||||||
local blk_ro=$(blockdev --getro "$2")
|
local blk_ro=$(blockdev --getro "$2")
|
||||||
[ "$blk_ro" -eq 1 ] && return 2
|
[ "$blk_ro" -eq 1 ] && return 2
|
||||||
eval "$CMD1" | eval "$CMD2" | cat - /dev/zero > "$2" 2>/dev/null
|
eval "$CMD1" | cat - /dev/zero > "$2" 2>/dev/null
|
||||||
elif [ -c "$2" ]; then
|
elif [ -c "$2" ]; then
|
||||||
flash_eraseall "$2" >&2
|
flash_eraseall "$2" >&2
|
||||||
eval "$CMD1" | eval "$CMD2" | nandwrite -p "$2" - >&2
|
eval "$CMD1" | nandwrite -p "$2" - >&2
|
||||||
else
|
else
|
||||||
ui_print "- Not block or char device, storing image"
|
ui_print "- Not block or char device, storing image"
|
||||||
eval "$CMD1" | eval "$CMD2" > "$2" 2>/dev/null
|
eval "$CMD1" > "$2" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -484,11 +395,6 @@ flash_image() {
|
|||||||
install_magisk() {
|
install_magisk() {
|
||||||
cd $MAGISKBIN
|
cd $MAGISKBIN
|
||||||
|
|
||||||
if [ ! -c $BOOTIMAGE ]; then
|
|
||||||
eval $BOOTSIGNER -verify < $BOOTIMAGE && BOOTSIGNED=true
|
|
||||||
$BOOTSIGNED && ui_print "- Boot image is signed with AVB 1.0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Source the boot patcher
|
# Source the boot patcher
|
||||||
SOURCEDMODE=true
|
SOURCEDMODE=true
|
||||||
. ./boot_patch.sh "$BOOTIMAGE"
|
. ./boot_patch.sh "$BOOTIMAGE"
|
||||||
@ -596,19 +502,6 @@ check_data() {
|
|||||||
$DATA_DE && set_nvbase "/data/adb"
|
$DATA_DE && set_nvbase "/data/adb"
|
||||||
}
|
}
|
||||||
|
|
||||||
find_magisk_apk() {
|
|
||||||
local DBAPK
|
|
||||||
[ -z $APK ] && APK=/data/app/com.topjohnwu.magisk*/base.apk
|
|
||||||
[ -f $APK ] || APK=/data/app/*/com.topjohnwu.magisk*/base.apk
|
|
||||||
if [ ! -f $APK ]; then
|
|
||||||
DBAPK=$(magisk --sqlite "SELECT value FROM strings WHERE key='requester'" 2>/dev/null | cut -d= -f2)
|
|
||||||
[ -z $DBAPK ] && DBAPK=$(strings $NVBASE/magisk.db | grep -oE 'requester..*' | cut -c10-)
|
|
||||||
[ -z $DBAPK ] || APK=/data/user_de/0/$DBAPK/dyn/current.apk
|
|
||||||
[ -f $APK ] || [ -z $DBAPK ] || APK=/data/data/$DBAPK/dyn/current.apk
|
|
||||||
fi
|
|
||||||
[ -f $APK ] || ui_print "! Unable to detect Magisk app APK for BootSigner"
|
|
||||||
}
|
|
||||||
|
|
||||||
run_migrations() {
|
run_migrations() {
|
||||||
local LOCSHA1
|
local LOCSHA1
|
||||||
local TARGET
|
local TARGET
|
||||||
@ -830,8 +723,3 @@ install_module() {
|
|||||||
|
|
||||||
TMPDIR=/dev/tmp
|
TMPDIR=/dev/tmp
|
||||||
set_nvbase "/data/adb"
|
set_nvbase "/data/adb"
|
||||||
|
|
||||||
# Bootsigner related stuff
|
|
||||||
BOOTSIGNERCLASS=com.topjohnwu.magisk.signing.SignBoot
|
|
||||||
BOOTSIGNER='/system/bin/dalvikvm -Xnoimage-dex2oat -cp $APK $BOOTSIGNERCLASS'
|
|
||||||
BOOTSIGNED=false
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user