From 2af45bacb4306bbdfb55094c3826e1d0d666eda7 Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Fri, 13 May 2016 18:44:48 -0700 Subject: [PATCH] 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 --- .../core/DefaultApkSignerEngine.java | 41 +++++++++++++++---- .../core/internal/apk/v1/V1SchemeSigner.java | 8 ++++ 2 files changed, 40 insertions(+), 9 deletions(-) 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 30d40110d..dae3c5eb4 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 com.android.apksigner.core.util.DataSource; 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 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { GetJarEntryDataDigestRequest dataDigestRequest = new GetJarEntryDataDigestRequest( entryName, - V1SchemeSigner.getMessageDigestInstance(mV1ContentDigestAlgorithm)); + V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm)); mOutputJarEntryDigestRequests.put(entryName, dataDigestRequest); mOutputJarEntryDigests.remove(entryName); return dataDigestRequest; @@ -590,9 +591,9 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { 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 class DefaultApkSignerEngine implements ApkSignerEngine { public DataSink getDataSink() { synchronized (mLock) { checkNotDone(); + if (mBuf == null) { + mBuf = new ByteArrayOutputStreamSink(); + } return mBuf; } } @@ -640,7 +644,7 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { if (!mDone) { throw new IllegalStateException("Not yet done"); } - return mBuf.getData(); + return (mBuf != null) ? mBuf.getData() : new byte[0]; } } } @@ -650,17 +654,17 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { */ 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 class DefaultApkSignerEngine implements ApkSignerEngine { 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 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { 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 b99cdeccc..8b59b8eb0 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 @@ -168,6 +168,14 @@ public abstract class V1SchemeSigner { } } + /** + * 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.