Skip to content

Commit

Permalink
1. Optimize patch speed
Browse files Browse the repository at this point in the history
  • Loading branch information
ZaneYork committed Feb 10, 2021
1 parent 3763f77 commit b9cc00a
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 193 deletions.
49 changes: 25 additions & 24 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
-keep class pxb.android.** { *; }
-keep class net.fornwall.apksigner.** { *; }
-keep class com.android.apksig.** { *; }
-keep class com.fansin.message.tool.core.BufferedRandomAccessFile { *; }

#Warning:org.bouncycastle.jce.provider.X509LDAPCertStoreSpi: can't find referenced class javax.naming.NamingEnumeration
-dontwarn javax.naming.**
Expand All @@ -162,27 +163,27 @@ public static java.lang.String TABLENAME;
# If you do NOT use RxJava:
-dontwarn rx.**

-keep class com.sun.org.apache.xml.internal.utils.PrefixResolver
-keep class java.rmi.Remote
-keep class java.rmi.server.*
-keep class javax.annotation.processing.AbstractProcessor
-keep class javax.el.*
-keep class javax.servlet.http.*
-keep class javax.servlet.jsp.el.VariableResolver
-keep class javax.servlet.jsp.*
-keep class javax.servlet.jsp.tagext.*
-keep class javax.servlet.*
-keep class javax.swing.JTree
-keep class javax.swing.tree.TreeNode
-keep class lombok.core.configuration.ConfigurationKey
-keep class org.apache.tools.ant.Task
-keep class org.apache.tools.ant.taskdefs.MatchingTask
-keep class org.apache.xml.utils.PrefixResolver
-keep class org.jaxen.dom.*
-keep class org.jaxen.dom4j.Dom4jXPath
-keep class org.jaxen.jdom.JDOMXPath
-keep class org.jaxen.*
-keep class org.jdom.output.XMLOutputter
-keep class org.python.core.PyObject
-keep class org.python.util.PythonInterpreter
-keep class org.zeroturnaround.javarebel.ClassEventListener
-dontwarn com.sun.org.apache.xml.internal.utils.PrefixResolver
-dontwarn java.rmi.Remote
-dontwarn java.rmi.server.*
-dontwarn javax.annotation.processing.AbstractProcessor
-dontwarn javax.el.*
-dontwarn javax.servlet.http.*
-dontwarn javax.servlet.jsp.el.VariableResolver
-dontwarn javax.servlet.jsp.*
-dontwarn javax.servlet.jsp.tagext.*
-dontwarn javax.servlet.*
-dontwarn javax.swing.JTree
-dontwarn javax.swing.tree.TreeNode
-dontwarn lombok.core.configuration.ConfigurationKey
-dontwarn org.apache.tools.ant.Task
-dontwarn org.apache.tools.ant.taskdefs.MatchingTask
-dontwarn org.apache.xml.utils.PrefixResolver
-dontwarn org.jaxen.dom.*
-dontwarn org.jaxen.dom4j.Dom4jXPath
-dontwarn org.jaxen.jdom.JDOMXPath
-dontwarn org.jaxen.*
-dontwarn org.jdom.output.XMLOutputter
-dontwarn org.python.core.PyObject
-dontwarn org.python.util.PythonInterpreter
-dontwarn org.zeroturnaround.javarebel.ClassEventListener
114 changes: 56 additions & 58 deletions app/src/main/java/com/android/apksig/ApkVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@
import com.android.apksig.apk.ApkUtils;
import com.android.apksig.internal.apk.AndroidBinXmlParser;
import com.android.apksig.internal.apk.ApkSigningBlockUtils;
import com.android.apksig.internal.apk.v1.V1SchemeVerifier;
import com.android.apksig.internal.apk.ContentDigestAlgorithm;
import com.android.apksig.internal.apk.SignatureAlgorithm;
import com.android.apksig.internal.apk.v1.V1SchemeVerifier;
import com.android.apksig.internal.apk.v2.V2SchemeVerifier;
import com.android.apksig.internal.apk.v3.V3SchemeVerifier;
import com.android.apksig.internal.util.AndroidSdkVersion;
import com.android.apksig.internal.zip.CentralDirectoryRecord;
import com.android.apksig.util.DataSource;
import com.android.apksig.util.DataSources;
import com.android.apksig.util.RunnablesExecutor;
import com.android.apksig.zip.ZipFormatException;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
Expand All @@ -47,6 +47,10 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;

/**
* APK signature verifier which mimics the behavior of the Android platform.
Expand Down Expand Up @@ -211,54 +215,31 @@ private Result verify(DataSource apk)
// include v2 and/or v3 signatures. If none is found, it falls back to JAR signature
// verification. If the signature is found but does not verify, the APK is rejected.
Set<Integer> foundApkSigSchemeIds = new HashSet<>(2);
if (maxSdkVersion >= AndroidSdkVersion.N) {
RunnablesExecutor executor = RunnablesExecutor.SINGLE_THREADED;
// Android P and newer attempts to verify APKs using APK Signature Scheme v3
if (maxSdkVersion >= AndroidSdkVersion.P) {
try {
ApkSigningBlockUtils.Result v3Result =
V3SchemeVerifier.verify(
executor,
apk,
zipSections,
Math.max(minSdkVersion, AndroidSdkVersion.P),
maxSdkVersion);
foundApkSigSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
result.mergeFrom(v3Result);
} catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) {
// v3 signature not required
}
if (result.containsErrors()) {
return result;
}
}

// Attempt to verify the APK using v2 signing if necessary. Platforms prior to Android P
// ignore APK Signature Scheme v3 signatures and always attempt to verify either JAR or
// APK Signature Scheme v2 signatures. Android P onwards verifies v2 signatures only if
// no APK Signature Scheme v3 (or newer scheme) signatures were found.
if (minSdkVersion < AndroidSdkVersion.P || foundApkSigSchemeIds.isEmpty()) {
try {
ApkSigningBlockUtils.Result v2Result =
V2SchemeVerifier.verify(
executor,
apk,
zipSections,
supportedSchemeNames,
foundApkSigSchemeIds,
Math.max(minSdkVersion, AndroidSdkVersion.N),
maxSdkVersion);
foundApkSigSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
result.mergeFrom(v2Result);
} catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) {
// v2 signature not required
}
if (result.containsErrors()) {
return result;
foundApkSigSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
FutureTask<ApkSigningBlockUtils.Result> taskV2 = new FutureTask<>(() -> {
if (maxSdkVersion >= AndroidSdkVersion.N) {
// Attempt to verify the APK using v2 signing if necessary. Platforms prior to Android P
// ignore APK Signature Scheme v3 signatures and always attempt to verify either JAR or
// APK Signature Scheme v2 signatures. Android P onwards verifies v2 signatures only if
// no APK Signature Scheme v3 (or newer scheme) signatures were found.
if (minSdkVersion < AndroidSdkVersion.P || foundApkSigSchemeIds.isEmpty()) {
try {
RunnablesExecutor executor = RunnablesExecutor.SINGLE_THREADED;
return V2SchemeVerifier.verify(
executor,
apk,
zipSections,
supportedSchemeNames,
foundApkSigSchemeIds,
Math.max(minSdkVersion, AndroidSdkVersion.N),
maxSdkVersion);
} catch (ApkSigningBlockUtils.SignatureNotFoundException ignored) {
// v2 signature not required
}
}
}
}

return null;
});
// Android O and newer requires that APKs targeting security sandbox version 2 and higher
// are signed using APK Signature Scheme v2 or newer.
if (maxSdkVersion >= AndroidSdkVersion.O) {
Expand All @@ -280,16 +261,27 @@ private Result verify(DataSource apk)
// ignore APK Signature Scheme v2 signatures and always attempt to verify JAR signatures.
// Android N onwards verifies JAR signatures only if no APK Signature Scheme v2 (or newer
// scheme) signatures were found.
if ((minSdkVersion < AndroidSdkVersion.N) || (foundApkSigSchemeIds.isEmpty())) {
V1SchemeVerifier.Result v1Result =
V1SchemeVerifier.verify(
apk,
zipSections,
supportedSchemeNames,
foundApkSigSchemeIds,
minSdkVersion,
maxSdkVersion);
result.mergeFrom(v1Result);
FutureTask<V1SchemeVerifier.Result> taskV1 = new FutureTask<>(() -> {
if ((minSdkVersion < AndroidSdkVersion.N) || (foundApkSigSchemeIds.isEmpty())) {
return V1SchemeVerifier.verify(
apk,
zipSections,
supportedSchemeNames,
foundApkSigSchemeIds,
minSdkVersion,
maxSdkVersion);
}
return null;
});
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
executorService.submit(taskV1);
executorService.submit(taskV2);
executorService.shutdown();
try {
result.mergeFrom(taskV1.get());
result.mergeFrom(taskV2.get());
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
if (result.containsErrors()) {
return result;
Expand Down Expand Up @@ -632,6 +624,9 @@ public List<IssueWithParams> getWarnings() {
}

private void mergeFrom(V1SchemeVerifier.Result source) {
if(source == null) {
return;
}
mVerifiedUsingV1Scheme = source.verified;
mErrors.addAll(source.getErrors());
mWarnings.addAll(source.getWarnings());
Expand All @@ -644,6 +639,9 @@ private void mergeFrom(V1SchemeVerifier.Result source) {
}

private void mergeFrom(ApkSigningBlockUtils.Result source) {
if(source == null) {
return;
}
switch (source.signatureSchemeVersion) {
case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
mVerifiedUsingV2Scheme = source.verified;
Expand Down
37 changes: 21 additions & 16 deletions app/src/main/java/com/android/apksig/DefaultApkSignerEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import com.android.apksig.util.DataSink;
import com.android.apksig.util.DataSinks;
import com.android.apksig.util.DataSource;

import com.android.apksig.util.RunnablesExecutor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
Expand All @@ -53,7 +53,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.StreamSupport;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Default implementation of {@link ApkSignerEngine}.
Expand Down Expand Up @@ -432,21 +433,25 @@ public Set<String> initWith(byte[] manifestBytes, Set<String> entryNames) {
Pair<ManifestParser.Section, Map<String, ManifestParser.Section>> sections =
V1SchemeVerifier.parseManifest(manifestBytes, entryNames, dummyResult);
String alg = V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm);
for (Map.Entry<String, ManifestParser.Section> entry: sections.getSecond().entrySet()) {
String entryName = entry.getKey();
if (V1SchemeSigner.isJarEntryDigestNeededInManifest(entry.getKey()) &&
isDebuggable(entryName)) {

Optional<V1SchemeVerifier.NamedDigest> extractedDigest =
V1SchemeVerifier.getDigestsToVerify(
entry.getValue(), "-Digest", mMinSdkVersion, Integer.MAX_VALUE).stream()
.filter(d -> d.jcaDigestAlgorithm == alg)
.findFirst();

extractedDigest.ifPresent(
namedDigest -> mOutputJarEntryDigests.put(entryName, namedDigest.digest));
}
Stream<Map.Entry<String, ManifestParser.Section>> entryStream;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
entryStream = sections.getSecond().entrySet().parallelStream();
}
else {
entryStream = sections.getSecond().entrySet().stream();
}
entryStream.filter(entry->V1SchemeSigner.isJarEntryDigestNeededInManifest(entry.getKey()) &&
isDebuggable(entry.getKey()) && entryNames.contains(entry.getKey())).forEach(entry->{
Optional<V1SchemeVerifier.NamedDigest> extractedDigest =
V1SchemeVerifier.getDigestsToVerify(
entry.getValue(), "-Digest", mMinSdkVersion, Integer.MAX_VALUE).stream()
.filter(d -> d.jcaDigestAlgorithm.equals(alg))
.findFirst();

extractedDigest.ifPresent(
namedDigest -> mOutputJarEntryDigests.put(entry.getKey(), namedDigest.digest));

});
return mOutputJarEntryDigests.keySet();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ public void feed(long offset, long size, DataSink sink) throws IOException {
}

for (DataSource src : mSources) {
long srcSize = src.size();
// Offset is beyond the current source. Skip.
if (offset >= src.size()) {
offset -= src.size();
if (offset >= srcSize) {
offset -= srcSize;
continue;
}

// If the remaining is enough, finish it.
long remaining = src.size() - offset;
long remaining = srcSize - offset;
if (remaining >= size) {
src.feed(offset, size, sink);
break;
Expand Down
Loading

0 comments on commit b9cc00a

Please sign in to comment.