Improve concurrency for JAR entry inspection requests.
This moves the creation of potentially expensive objects from the
thread which creates JAR entry inspection requests, to the thread
which fulfills these requests, increasig concurrency opportunities.
Bug: 27461702
Change-Id: If753b2de7fb04ee5e2e4bbcb27d42269d7fa5def
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java b/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java
index 30d4011..dae3c5e 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java
@@ -28,6 +28,7 @@
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
@@ -227,7 +228,7 @@
GetJarEntryDataDigestRequest dataDigestRequest =
new GetJarEntryDataDigestRequest(
entryName,
- V1SchemeSigner.getMessageDigestInstance(mV1ContentDigestAlgorithm));
+ V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm));
mOutputJarEntryDigestRequests.put(entryName, dataDigestRequest);
mOutputJarEntryDigests.remove(entryName);
return dataDigestRequest;
@@ -590,9 +591,9 @@
private static class GetJarEntryDataRequest implements InspectJarEntryRequest {
private final String mEntryName;
private final Object mLock = new Object();
- private final ByteArrayOutputStreamSink mBuf = new ByteArrayOutputStreamSink();
private boolean mDone;
+ private ByteArrayOutputStreamSink mBuf;
private GetJarEntryDataRequest(String entryName) {
mEntryName = entryName;
@@ -607,6 +608,9 @@
public DataSink getDataSink() {
synchronized (mLock) {
checkNotDone();
+ if (mBuf == null) {
+ mBuf = new ByteArrayOutputStreamSink();
+ }
return mBuf;
}
}
@@ -640,7 +644,7 @@
if (!mDone) {
throw new IllegalStateException("Not yet done");
}
- return mBuf.getData();
+ return (mBuf != null) ? mBuf.getData() : new byte[0];
}
}
}
@@ -650,17 +654,17 @@
*/
private static class GetJarEntryDataDigestRequest implements InspectJarEntryRequest {
private final String mEntryName;
- private final MessageDigest mMessageDigest;
- private final DataSink mDataSink;
+ private final String mJcaDigestAlgorithm;
private final Object mLock = new Object();
private boolean mDone;
+ private DataSink mDataSink;
+ private MessageDigest mMessageDigest;
private byte[] mDigest;
- private GetJarEntryDataDigestRequest(String entryName, MessageDigest digest) {
+ private GetJarEntryDataDigestRequest(String entryName, String jcaDigestAlgorithm) {
mEntryName = entryName;
- mMessageDigest = digest;
- mDataSink = new MessageDigestSink(new MessageDigest[] {mMessageDigest});
+ mJcaDigestAlgorithm = jcaDigestAlgorithm;
}
@Override
@@ -672,10 +676,27 @@
public DataSink getDataSink() {
synchronized (mLock) {
checkNotDone();
+ if (mDataSink == null) {
+ mDataSink = new MessageDigestSink(new MessageDigest[] {getMessageDigest()});
+ }
return mDataSink;
}
}
+ private MessageDigest getMessageDigest() {
+ synchronized (mLock) {
+ if (mMessageDigest == null) {
+ try {
+ mMessageDigest = MessageDigest.getInstance(mJcaDigestAlgorithm);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(
+ mJcaDigestAlgorithm + " MessageDigest not available", e);
+ }
+ }
+ return mMessageDigest;
+ }
+ }
+
@Override
public void done() {
synchronized (mLock) {
@@ -683,7 +704,9 @@
return;
}
mDone = true;
- mDigest = mMessageDigest.digest();
+ mDigest = getMessageDigest().digest();
+ mMessageDigest = null;
+ mDataSink = null;
}
}
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
index b99cdec..8b59b8e 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
@@ -169,6 +169,14 @@
}
/**
+ * Returns the JCA {@link MessageDigest} algorithm corresponding to the provided digest
+ * algorithm.
+ */
+ public static String getJcaMessageDigestAlgorithm(DigestAlgorithm digestAlgorithm) {
+ return digestAlgorithm.getJcaMessageDigestAlgorithm();
+ }
+
+ /**
* Returns {@code true} if the provided JAR entry must be mentioned in signed JAR archive's
* manifest.
*/