am bc864b48: Merge "Cipher: iterate through services first"
* commit 'bc864b48689ac9374ec88ab0d8a719666dc8a8e6':
Cipher: iterate through services first
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index b27ea88..c455119 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -512,8 +512,9 @@
// Try each of the transforms and keep track of the first exception
// encountered.
Exception cause = null;
- for (Transform transform : transforms) {
- if (provider != null) {
+
+ if (provider != null) {
+ for (Transform transform : transforms) {
Provider.Service service = provider.getService(SERVICE, transform.name);
if (service == null) {
continue;
@@ -521,22 +522,40 @@
return tryTransformWithProvider(initParams, transformParts, transform.needToSet,
service);
}
- ArrayList<Provider.Service> services = ENGINE.getServices(transform.name);
- if (services == null || services.isEmpty()) {
- continue;
- }
+ } else {
+ ArrayList<Provider.Service> services = ENGINE.getServices();
for (Provider.Service service : services) {
- if (initParams == null || initParams.key == null
- || service.supportsParameter(initParams.key)) {
- try {
- Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
- transformParts, transform.needToSet, service);
- if (sap != null) {
- return sap;
+ String serviceAlgorithmUC = service.getAlgorithm().toUpperCase(Locale.US);
+ for (Transform transform : transforms) {
+ // Check that this service offers the algorithm we're after
+ // since none of the services have been filtered yet.
+ boolean matchesAlgorithm = false;
+ if (transform.name.equals(serviceAlgorithmUC)) {
+ matchesAlgorithm = true;
+ } else {
+ for (String alias : Engine.door.getAliases(service)) {
+ if (transform.name.equals(alias.toUpperCase(Locale.US))) {
+ matchesAlgorithm = true;
+ break;
+ }
}
- } catch (Exception e) {
- if (cause == null) {
- cause = e;
+ }
+ if (!matchesAlgorithm) {
+ continue;
+ }
+
+ if (initParams == null || initParams.key == null
+ || service.supportsParameter(initParams.key)) {
+ try {
+ Engine.SpiAndProvider sap = tryTransformWithProvider(initParams,
+ transformParts, transform.needToSet, service);
+ if (sap != null) {
+ return sap;
+ }
+ } catch (Exception e) {
+ if (cause == null) {
+ cause = e;
+ }
}
}
}
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index 1c794e5..3c929c4 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -152,6 +152,14 @@
}
/**
+ * Returns a list of all providers for this type of service or {@code null}
+ * if no matches were found.
+ */
+ public ArrayList<Provider.Service> getServices() {
+ return Services.getServices(serviceName);
+ }
+
+ /**
* Returns a list of all possible matches for a given algorithm. Returns
* {@code null} if no matches were found.
*/
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index 234f4a2..232b6d2 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -21,7 +21,7 @@
import java.security.Security;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Locale;
+import java.util.Iterator;
/**
@@ -134,12 +134,37 @@
}
/**
+ * Looks up the requested service by type. The service {@code type} and
+ * should be provided in the same format used when registering a service
+ * with a provider, for example, "KeyFactory". Callers can cache the
+ * returned service information but such caches should be validated against
+ * the result of Service.getCacheVersion() before use. Returns {@code null}
+ * if there are no services of the given {@code type} found.
+ */
+ public static synchronized ArrayList<Provider.Service> getServices(String type) {
+ ArrayList<Provider.Service> services = null;
+ for (Provider p : providers) {
+ Iterator<Provider.Service> i = p.getServices().iterator();
+ while (i.hasNext()) {
+ Provider.Service s = i.next();
+ if (type.equals(s.getType())) {
+ if (services == null) {
+ services = new ArrayList<>(providers.size());
+ }
+ services.add(s);
+ }
+ }
+ }
+ return services;
+ }
+
+ /**
* Looks up the requested service by type and algorithm. The service
* {@code type} and should be provided in the same format used when
- * registering a service with a provider, for example, "KeyFactory.RSA".
- * Callers can cache the returned service information but such caches should
- * be validated against the result of Service.getCacheVersion() before use.
- * Returns {@code null} if there are no services found.
+ * registering a service with a provider, for example, "KeyFactory" and
+ * "RSA". Callers can cache the returned service information but such caches
+ * should be validated against the result of Service.getCacheVersion()
+ * before use. Returns {@code null} if there are no services found.
*/
public static synchronized ArrayList<Provider.Service> getServices(String type,
String algorithm) {
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 13d54b4..bad8a74 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -979,6 +979,76 @@
}
}
+ public void testCipher_getInstance_CorrectPriority_AlgorithmOnlyFirst() throws Exception {
+ Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+ Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") {
+ public void setup() {
+ put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderOnlyAlgorithm);
+ Security.addProvider(mockProviderFullTransformSpecified);
+ try {
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+ assertEquals(mockProviderOnlyAlgorithm, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderOnlyAlgorithm.getName());
+ Security.removeProvider(mockProviderFullTransformSpecified.getName());
+ }
+ }
+
+ public void testCipher_getInstance_CorrectPriority_FullTransformFirst() throws Exception {
+ Provider mockProviderOnlyAlgorithm = new MockProvider("MockProviderOnlyAlgorithm") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+ Provider mockProviderFullTransformSpecified = new MockProvider("MockProviderFull") {
+ public void setup() {
+ put("Cipher.FOO/FOO/FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderFullTransformSpecified);
+ Security.addProvider(mockProviderOnlyAlgorithm);
+ try {
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+ assertEquals(mockProviderFullTransformSpecified, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderOnlyAlgorithm.getName());
+ Security.removeProvider(mockProviderFullTransformSpecified.getName());
+ }
+ }
+
+ public void testCipher_getInstance_CorrectPriority_AliasedAlgorithmFirst() throws Exception {
+ Provider mockProviderAliasedAlgorithm = new MockProvider("MockProviderAliasedAlgorithm") {
+ public void setup() {
+ put("Cipher.BAR", MockCipherSpi.AllKeyTypes.class.getName());
+ put("Alg.Alias.Cipher.FOO", "BAR");
+ }
+ };
+ Provider mockProviderAlgorithmOnly = new MockProvider("MockProviderAlgorithmOnly") {
+ public void setup() {
+ put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName());
+ }
+ };
+
+ Security.addProvider(mockProviderAliasedAlgorithm);
+ Security.addProvider(mockProviderAlgorithmOnly);
+ try {
+ Cipher c = Cipher.getInstance("FOO/FOO/FOO");
+ assertEquals(mockProviderAliasedAlgorithm, c.getProvider());
+ } finally {
+ Security.removeProvider(mockProviderAliasedAlgorithm.getName());
+ Security.removeProvider(mockProviderAlgorithmOnly.getName());
+ }
+ }
+
public void testCipher_getInstance_WrongType_Failure() throws Exception {
Provider mockProviderInvalid = new MockProvider("MockProviderInvalid") {
public void setup() {