Merge "Correct docs based on recent behavior change"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 9f6d827..fb0b207 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -116,16 +116,6 @@
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
include $(BUILD_JAVA_LIBRARY)
-# Path to the ICU4C data files in the Android device file system:
-icu4c_data := /system/usr/icu
-# TODO: It's quite hideous that this double-slash between icu4j and main is required.
-# It's because we provide a variable substition of the make-rule generated jar command
-# to substitute a processed ICUProperties.config file in place of the original.
-#
-# We can avoid this by filtering out ICUConfig.properties from our list of resources.
-icu4j_config_root := $(LOCAL_PATH)/../external/icu/icu4j//main/classes/core/src
-include external/icu/icu4j/adjust_icudt_path.mk
-
ifeq ($(LIBCORE_SKIP_TESTS),)
# Make the core-tests library.
include $(CLEAR_VARS)
diff --git a/benchmarks/src/benchmarks/regression/ProviderBenchmark.java b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
new file mode 100644
index 0000000..649aa01
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import java.security.Provider;
+import java.security.Security;
+import javax.crypto.Cipher;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import javax.net.ssl.SSLSocketFactory;
+
+public class ProviderBenchmark extends SimpleBenchmark {
+ public void timeStableProviders(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ Cipher c = Cipher.getInstance("RSA");
+ }
+ }
+
+ public void timeWithNewProvider(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ Security.addProvider(new MockProvider());
+ try {
+ Cipher c = Cipher.getInstance("RSA");
+ } finally {
+ Security.removeProvider("Mock");
+ }
+ }
+ }
+
+ private static class MockProvider extends Provider {
+ public MockProvider() {
+ super("Mock", 1.0, "Mock me!");
+ }
+ }
+}
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 6470e36..6aac9eb 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1509,5 +1509,13 @@
"libcore.java.util.zip.Zip64FileTest#testZip64Support_totalLargerThan4G",
"libcore.java.util.zip.Zip64FileTest#testZip64Support_hugeEntry"
]
+},
+{
+ description: "OsTest.test_PacketSocketAddress needs CAP_NET_RAW",
+ bug: 19764047,
+ result: EXEC_FAILED,
+ names: [
+ "libcore.io.OsTest#test_PacketSocketAddress"
+ ]
}
]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
index 277abce..8b4844c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
@@ -2217,7 +2217,7 @@
long[] b = new long[a.length];
for (int i = 0; i < a.length; i++) {
- b[i] = (int) a[i];
+ b[i] = (long) a[i];
}
return b;
}
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index 99c562f..388f34c 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -39,7 +39,6 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.ArtMethod;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
@@ -141,9 +140,6 @@
/** Short-cut to dexCache.strings */
private transient String[] dexCacheStrings;
- /** static, private, and <init> methods. */
- private transient ArtMethod[] directMethods;
-
/**
* The interface table (iftable_) contains pairs of a interface class and an array of the
* interface methods. There is one pair per interface supported by this class. That
@@ -169,20 +165,20 @@
/** If class verify fails, we must return same error on subsequent tries. */
private transient Class<?> verifyErrorClass;
- /** Virtual methods defined in this class; invoked through vtable. */
- private transient ArtMethod[] virtualMethods;
-
/**
* Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass
* is copied in, and virtual methods from our class either replace those from the super or are
* appended. For abstract classes, methods may be created in the vtable that aren't in
* virtual_ methods_ for miranda methods.
*/
- private transient ArtMethod[] vtable;
+ private transient Object vtable;
/** access flags; low 16 bits are defined by VM spec */
private transient int accessFlags;
+ /** static, private, and <init> methods. */
+ private transient long directMethods;
+
/**
* Instance fields. These describe the layout of the contents of an Object. Note that only the
* fields directly declared by this class are listed in iFields; fields declared by a
@@ -196,6 +192,8 @@
/** Static fields */
private transient long sFields;
+ /** Virtual methods defined in this class; invoked through vtable. */
+ private transient long virtualMethods;
/**
* Total size of the Class instance; used when allocating storage on GC heap.
@@ -222,6 +220,9 @@
*/
private transient volatile int dexTypeIndex;
+ /** Number of direct methods. */
+ private transient int numDirectMethods;
+
/** Number of instance fields. */
private transient int numInstanceFields;
@@ -234,6 +235,9 @@
/** Number of static fields. */
private transient int numStaticFields;
+ /** Number of virtual methods. */
+ private transient int numVirtualMethods;
+
/**
* Total object size; used when allocating storage on GC heap. For interfaces and abstract
* classes this will be zero. See also {@link Class#classSize}.
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index c047018..73e35cd 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -33,7 +33,6 @@
package java.lang;
import com.android.dex.Dex;
-import java.lang.reflect.ArtMethod;
/**
* A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
@@ -49,7 +48,7 @@
* References to methods as they become resolved following interpreter semantics. May refer to
* methods defined in other dex files.
*/
- ArtMethod[] resolvedMethods;
+ Object resolvedMethods;
/**
* References to fields as they become resolved following interpreter semantics. May refer to
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index 0ac15f9..95d90cc 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -51,10 +51,11 @@
/**
* The ArtMethod associated with this Method, requried for dispatching due to entrypoints
+ * Classloader is held live by the declaring class.
* Hidden to workaround b/16828157.
* @hide
*/
- protected ArtMethod artMethod;
+ protected long artMethod;
/** Method's declaring class */
protected Class<?> declaringClass;
diff --git a/libart/src/main/java/java/lang/reflect/ArtMethod.java b/libart/src/main/java/java/lang/reflect/ArtMethod.java
deleted file mode 100644
index 84e6b48..0000000
--- a/libart/src/main/java/java/lang/reflect/ArtMethod.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.reflect;
-
-import com.android.dex.Dex;
-import java.lang.annotation.Annotation;
-import libcore.reflect.AnnotationAccess;
-import libcore.util.EmptyArray;
-
-/**
- * This class represents methods and constructors.
- * @hide
- */
-public final class ArtMethod {
- /* A note on the field order here, it reflects the same field order as laid out by ART. */
-
- /** Method's declaring class */
- private Class<?> declaringClass;
-
- /** Short-cut to declaringClass.dexCache.resolvedMethods */
- private ArtMethod[] dexCacheResolvedMethods;
-
- /** Short-cut to declaringClass.dexCache.resolvedTypes */
- /* package */ Class<?>[] dexCacheResolvedTypes;
-
- /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
- private int accessFlags;
-
- /* Dex file fields. The defining dex file is available via declaringClass.dexCache */
-
- /** The offset of the code item associated with this method within its defining dex file */
- private int dexCodeItemOffset;
-
- /** The method index of this method within its defining dex file */
- private int dexMethodIndex;
-
- /* End of dex file fields. */
-
- /**
- * Entry within a dispatch table for this method. For static/direct methods the index is
- * into the declaringClass.directMethods, for virtual methods the vtable and for
- * interface methods the ifTable.
- */
- private int methodIndex;
-
- /** Only created by ART directly. */
- private ArtMethod() {}
-}
diff --git a/luni/src/main/java/java/nio/ByteOrder.java b/luni/src/main/java/java/nio/ByteOrder.java
index 286c970..508c8ef 100644
--- a/luni/src/main/java/java/nio/ByteOrder.java
+++ b/luni/src/main/java/java/nio/ByteOrder.java
@@ -32,13 +32,10 @@
*/
public static final ByteOrder LITTLE_ENDIAN;
- private static native boolean isLittleEndian();
-
static {
- boolean isLittleEndian = isLittleEndian();
- BIG_ENDIAN = new ByteOrder("BIG_ENDIAN", isLittleEndian);
- LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN", !isLittleEndian);
- NATIVE_ORDER = isLittleEndian ? LITTLE_ENDIAN : BIG_ENDIAN;
+ BIG_ENDIAN = new ByteOrder("BIG_ENDIAN", true /* needs swap */);
+ LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN", false /* needs swap */);
+ NATIVE_ORDER = LITTLE_ENDIAN;
}
private final String name;
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
index 5dfdd9f..38be0c2 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
@@ -202,7 +202,7 @@
private void setPosition(CharBuffer out) {
if (out.hasArray()) {
- out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
+ out.position(out.position() + data[OUTPUT_OFFSET]);
} else {
out.put(output, 0, data[OUTPUT_OFFSET]);
}
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
index 1704b58..1a64ecc 100644
--- a/luni/src/main/java/java/security/Provider.java
+++ b/luni/src/main/java/java/security/Provider.java
@@ -368,8 +368,8 @@
}
/**
- * Get the service of the specified type
- *
+ * Get the service of the specified {@code type} (e.g. "SecureRandom",
+ * "Signature").
*/
synchronized Provider.Service getService(String type) {
updatePropertyServiceTable();
diff --git a/luni/src/main/java/java/security/Signature.java b/luni/src/main/java/java/security/Signature.java
index 3151058..795ccad 100644
--- a/luni/src/main/java/java/security/Signature.java
+++ b/luni/src/main/java/java/security/Signature.java
@@ -245,11 +245,12 @@
}
/**
- * Gets the SPI implementation backing this signature.
+ * Returns the {@code SignatureSpi} backing this {@code Signature} or {@code null} if no
+ * {@code SignatureSpi} is backing this {@code Signature}.
*
* @hide
*/
- public SignatureSpi getSpi() {
+ public SignatureSpi getCurrentSpi() {
return null;
}
@@ -739,12 +740,16 @@
/**
* Convenience call when the Key is not available.
- *
- * @hide
*/
- @Override
- public SignatureSpi getSpi() {
+ private SignatureSpi getSpi() {
return getSpi(null);
}
+
+ @Override
+ public SignatureSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
+ }
}
}
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 2f1d4f4..006d37b 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -297,8 +297,14 @@
return minusSign.charAt(0);
}
- throw new UnsupportedOperationException(
- "Minus sign spans multiple characters: " + minusSign);
+ // Return the minus sign from Locale.ROOT instead of crashing. None of libcore the parsers
+ // or formatters actually call this function, they use {@code getMinusSignString()} instead
+ // and that function always returns the correct (possibly multi-char) symbol.
+ //
+ // Callers of this method that format strings and expect them to be parseable by
+ // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+ // save them.
+ return '-';
}
/** @hide */
@@ -349,7 +355,15 @@
if (percent.length() == 1) {
return percent.charAt(0);
}
- throw new UnsupportedOperationException("Percent spans multiple characters: " + percent);
+
+ // Return the percent sign from Locale.ROOT instead of crashing. None of the libcore parsers
+ // or formatters actually call this function, they use {@code getPercentString()} instead
+ // and that function always returns the correct (possibly multi-char) symbol.
+ //
+ // Callers of this method that format strings and expect them to be parseable by
+ // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+ // save them.
+ return '%';
}
/**
@@ -601,6 +615,8 @@
new ObjectStreamField("serialVersionOnStream", int.class),
new ObjectStreamField("zeroDigit", char.class),
new ObjectStreamField("locale", Locale.class),
+ new ObjectStreamField("minusSignStr", String.class),
+ new ObjectStreamField("percentStr", String.class),
};
private void writeObject(ObjectOutputStream stream) throws IOException {
@@ -613,15 +629,21 @@
fields.put("groupingSeparator", getGroupingSeparator());
fields.put("infinity", infinity);
fields.put("intlCurrencySymbol", intlCurrencySymbol);
- fields.put("minusSign", getMinusSign());
fields.put("monetarySeparator", getMonetaryDecimalSeparator());
fields.put("NaN", NaN);
fields.put("patternSeparator", getPatternSeparator());
- fields.put("percent", getPercent());
fields.put("perMill", getPerMill());
fields.put("serialVersionOnStream", 3);
fields.put("zeroDigit", getZeroDigit());
fields.put("locale", locale);
+
+ // Hardcode values here for backwards compatibility. These values will only be used
+ // if we're de-serializing this object on an earlier version of android.
+ fields.put("minusSign", minusSign.length() == 1 ? minusSign.charAt(0) : '-');
+ fields.put("percent", percent.length() == 1 ? percent.charAt(0) : '%');
+
+ fields.put("minusSignStr", getMinusSignString());
+ fields.put("percentStr", getPercentString());
stream.writeFields();
}
@@ -634,10 +656,26 @@
setGroupingSeparator(fields.get("groupingSeparator", ','));
infinity = (String) fields.get("infinity", "");
intlCurrencySymbol = (String) fields.get("intlCurrencySymbol", "");
- setMinusSign(fields.get("minusSign", '-'));
NaN = (String) fields.get("NaN", "");
setPatternSeparator(fields.get("patternSeparator", ';'));
- setPercent(fields.get("percent", '%'));
+
+ // Special handling for minusSign and percent. If we've serialized the string versions of
+ // these fields, use them. If not, fall back to the single character versions. This can
+ // only happen if we're de-serializing an object that was written by an older version of
+ // android (something that's strongly discouraged anyway).
+ final String minusSignStr = (String) fields.get("minusSignStr", null);
+ if (minusSignStr != null) {
+ minusSign = minusSignStr;
+ } else {
+ setMinusSign(fields.get("minusSign", '-'));
+ }
+ final String percentStr = (String) fields.get("percentStr", null);
+ if (percentStr != null) {
+ percent = percentStr;
+ } else {
+ setPercent(fields.get("percent", '%'));
+ }
+
setPerMill(fields.get("perMill", '\u2030'));
setZeroDigit(fields.get("zeroDigit", '0'));
locale = (Locale) fields.get("locale", null);
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index 66d03ad..5a66c20 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -366,11 +366,25 @@
/**
* Convenience call when the Key is not available.
+ */
+ private CipherSpi getSpi() {
+ return getSpi(null);
+ }
+
+ /**
+ * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
+ * {@code CipherSpi} is backing this {@code Cipher}.
*
* @hide
*/
- public CipherSpi getSpi() {
- return getSpi(null);
+ public CipherSpi getCurrentSpi() {
+ if (specifiedSpi != null) {
+ return specifiedSpi;
+ }
+
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
/**
diff --git a/luni/src/main/java/javax/crypto/KeyAgreement.java b/luni/src/main/java/javax/crypto/KeyAgreement.java
index d27aa2e..1ba660d 100644
--- a/luni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/luni/src/main/java/javax/crypto/KeyAgreement.java
@@ -252,11 +252,21 @@
/**
* Convenience call when the Key is not available.
+ */
+ private KeyAgreementSpi getSpi() {
+ return getSpi(null);
+ }
+
+ /**
+ * Returns the {@code KeyAgreementSpi} backing this {@code KeyAgreement} or {@code null} if no
+ * {@code KeyAgreementSpi} is backing this {@code KeyAgreement}.
*
* @hide
*/
- public KeyAgreementSpi getSpi() {
- return getSpi(null);
+ public KeyAgreementSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
/**
diff --git a/luni/src/main/java/javax/crypto/Mac.java b/luni/src/main/java/javax/crypto/Mac.java
index 536f0c5..7da84e6 100644
--- a/luni/src/main/java/javax/crypto/Mac.java
+++ b/luni/src/main/java/javax/crypto/Mac.java
@@ -266,11 +266,21 @@
/**
* Convenience call when the Key is not available.
+ */
+ private MacSpi getSpi() {
+ return getSpi(null);
+ }
+
+ /**
+ * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
+ * backing this {@code Mac}.
*
* @hide
*/
- public MacSpi getSpi() {
- return getSpi(null);
+ public MacSpi getCurrentSpi() {
+ synchronized (initLock) {
+ return spiImpl;
+ }
}
/**
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index fd8570c..d2cb9ab 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -18,17 +18,11 @@
import android.system.ErrnoException;
import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.TimeZone;
import libcore.io.BufferIterator;
-import libcore.io.IoUtils;
import libcore.io.MemoryMappedFile;
/**
@@ -253,6 +247,13 @@
public boolean hasTimeZone(String id) throws IOException {
return cache.get(id) != null;
}
+
+ @Override protected void finalize() throws Throwable {
+ if (mappedFile != null) {
+ mappedFile.close();
+ }
+ super.finalize();
+ }
}
private ZoneInfoDB() {
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 855a8c7..1c794e5 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,7 +152,8 @@
}
/**
- * Returns a list of all possible matches for a given algorithm.
+ * Returns a list of all possible matches for a given algorithm. Returns
+ * {@code null} if no matches were found.
*/
public ArrayList<Provider.Service> getServices(String algorithm) {
int newCacheVersion = Services.getCacheVersion();
@@ -163,8 +164,7 @@
&& newCacheVersion == cacheEntry.cacheVersion) {
return cacheEntry.services;
}
- String name = this.serviceName + "." + algoUC;
- ArrayList<Provider.Service> services = Services.getServices(name);
+ ArrayList<Provider.Service> services = Services.getServices(serviceName, algoUC);
this.serviceCache = new ServiceCacheEntry(algoUC, newCacheVersion, services);
return services;
}
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 c81bf6b..5f3dfe0 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
@@ -29,16 +29,6 @@
* implementations for all "serviceName.algName".
*/
public class Services {
-
- /**
- * The HashMap that contains information about preferred implementations for
- * all serviceName.algName in the registered providers.
- * Set the initial size to 600 so we don't grow to 1024 by default because
- * initialization adds a few entries more than the growth threshold.
- */
- private static final HashMap<String, ArrayList<Provider.Service>> services
- = new HashMap<String, ArrayList<Provider.Service>>(600);
-
/**
* Save default SecureRandom service as well.
* Avoids similar provider/services iteration in SecureRandom constructor.
@@ -71,7 +61,6 @@
Provider p = (Provider) providerClass.newInstance();
providers.add(p);
providersNames.put(p.getName(), p);
- initServiceInfo(p);
return true;
} catch (ClassNotFoundException ignored) {
} catch (IllegalAccessException ignored) {
@@ -104,7 +93,7 @@
}
/**
- * Returns a copy of the registered providers as an array.
+ * Returns the actual registered providers.
*/
public static synchronized ArrayList<Provider> getProviders() {
return providers;
@@ -144,54 +133,39 @@
}
/**
- * Adds information about provider services into HashMap.
+ * 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.
*/
- public static synchronized void initServiceInfo(Provider p) {
- for (Provider.Service service : p.getServices()) {
- String type = service.getType();
- if (cachedSecureRandomService == null && type.equals("SecureRandom")) {
- cachedSecureRandomService = service;
- }
- String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US);
- appendServiceLocked(key, service);
- for (String alias : Engine.door.getAliases(service)) {
- key = type + "." + alias.toUpperCase(Locale.US);
- appendServiceLocked(key, service);
+ public static synchronized ArrayList<Provider.Service> getServices(String type,
+ String algorithm) {
+ ArrayList<Provider.Service> services = null;
+ for (Provider p : providers) {
+ Provider.Service s = p.getService(type, algorithm);
+ if (s != null) {
+ if (services == null) {
+ services = new ArrayList<>(providers.size());
+ }
+ services.add(s);
}
}
+ return services;
}
/**
- * Add or append the service to the key.
+ * Finds the first service offered of {@code type} and returns it.
*/
- private static void appendServiceLocked(String key, Provider.Service service) {
- ArrayList<Provider.Service> serviceList = services.get(key);
- if (serviceList == null) {
- serviceList = new ArrayList<Provider.Service>(1);
- services.put(key, serviceList);
+ private static synchronized Provider.Service getFirstServiceOfType(String type) {
+ for (Provider p : providers) {
+ Provider.Service s = Engine.door.getService(p, type);
+ if (s != null) {
+ return s;
+ }
}
- serviceList.add(service);
- }
-
- /**
- * Returns true if services does not contain any provider information.
- */
- public static synchronized boolean isEmpty() {
- return services.isEmpty();
- }
-
- /**
- * Looks up the requested service by type and algorithm. The
- * service key 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.
- */
- public static synchronized ArrayList<Provider.Service> getServices(String key) {
- return services.get(key);
+ return null;
}
/**
@@ -219,13 +193,7 @@
public static synchronized int getCacheVersion() {
if (needRefresh) {
cacheVersion++;
- synchronized (services) {
- services.clear();
- }
- cachedSecureRandomService = null;
- for (Provider p : providers) {
- initServiceInfo(p);
- }
+ cachedSecureRandomService = getFirstServiceOfType("SecureRandom");
needRefresh = false;
}
return cacheVersion;
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index acc1e4f..787a149 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -47,7 +47,6 @@
REGISTER(register_java_lang_StringToReal);
REGISTER(register_java_lang_System);
REGISTER(register_java_math_NativeBN);
- REGISTER(register_java_nio_ByteOrder);
REGISTER(register_java_text_Bidi);
REGISTER(register_java_util_jar_StrictJarFile);
REGISTER(register_java_util_regex_Matcher);
diff --git a/luni/src/main/native/java_nio_ByteOrder.cpp b/luni/src/main/native/java_nio_ByteOrder.cpp
deleted file mode 100644
index 3269bc2..0000000
--- a/luni/src/main/native/java_nio_ByteOrder.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ByteOrder"
-
-#include "JNIHelp.h"
-#include "JniConstants.h"
-
-static jboolean ByteOrder_isLittleEndian(JNIEnv*, jclass) {
- int i = 1;
- return *reinterpret_cast<jbyte*>(&i) == 1;
-}
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(ByteOrder, isLittleEndian, "!()Z"),
-};
-void register_java_nio_ByteOrder(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/nio/ByteOrder", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index 73ed7cb..78ec37a 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -27,7 +27,6 @@
java_lang_StringToReal.cpp \
java_lang_System.cpp \
java_math_NativeBN.cpp \
- java_nio_ByteOrder.cpp \
java_text_Bidi.cpp \
java_util_jar_StrictJarFile.cpp \
java_util_regex_Matcher.cpp \
diff --git a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
index 1078cd0..c57db71 100644
--- a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
+++ b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
@@ -16,6 +16,7 @@
package dalvik.system;
+import java.io.FilenameFilter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.io.File;
@@ -29,93 +30,41 @@
* Tests for the class {@link DexClassLoader}.
*/
public class DexClassLoaderTest extends TestCase {
- // Use /data not /sdcard because optimized cannot be noexec mounted
- private static final File WORKING_DIR;
- static {
- // First try to use the test runner directory for cts, fall back to
- // shell-writable directory for vogar
- File runner_dir = new File("/data/data/android.core.tests.runner");
- if (runner_dir.exists()) {
- WORKING_DIR = runner_dir;
- } else {
- WORKING_DIR = new File("/data/local/tmp");
- }
- }
- private static final File TMP_DIR = new File(WORKING_DIR, "loading-test");
private static final String PACKAGE_PATH = "dalvik/system/";
- private static final String JAR_NAME = "loading-test.jar";
- private static final String DEX_NAME = "loading-test.dex";
- private static final String JAR2_NAME = "loading-test2.jar";
- private static final String DEX2_NAME = "loading-test2.dex";
- private static final File JAR_FILE = new File(TMP_DIR, JAR_NAME);
- private static final File DEX_FILE = new File(TMP_DIR, DEX_NAME);
- private static final File JAR2_FILE = new File(TMP_DIR, JAR2_NAME);
- private static final File DEX2_FILE = new File(TMP_DIR, DEX2_NAME);
- private static final File DEFAULT_OPTIMIZED_DIR = new File(TMP_DIR, "optimized");
- // Init tests need to use different optimized directories because the tests are executed in the
- // same runtime. This means we can't reliably count the number of generated file since they
- // might be cached by the runtime.
- private static final File INIT1_OPTIMIZED_DIR = new File(TMP_DIR, "optimized_init1");
- private static final File INIT2_OPTIMIZED_DIR = new File(TMP_DIR, "optimized_init2");
- private static enum Configuration {
- /** just one classpath element, a raw dex file */
- ONE_DEX(1, DEX_FILE),
- ONE_DEX_INIT(INIT1_OPTIMIZED_DIR, 1, DEX_FILE),
-
- /** just one classpath element, a jar file */
- ONE_JAR(1, JAR_FILE),
- ONE_JAR_INIT(INIT1_OPTIMIZED_DIR, 1, JAR_FILE),
-
- /** two classpath elements, both raw dex files */
- TWO_DEX(2, DEX_FILE, DEX2_FILE),
- TWO_DEX_INIT(INIT2_OPTIMIZED_DIR, 2, DEX_FILE, DEX2_FILE),
-
- /** two classpath elements, both jar files */
- TWO_JAR(2, JAR_FILE, JAR2_FILE),
- TWO_JAR_INIT(INIT2_OPTIMIZED_DIR, 2, JAR_FILE, JAR2_FILE);
-
- public final int expectedFiles;
- public final File optimizedDir;
- public final String path;
-
- Configuration(int expectedFiles, File... files) {
- this(DEFAULT_OPTIMIZED_DIR, expectedFiles, files);
- }
-
- Configuration(File optimizedDir, int expectedFiles, File... files) {
- assertTrue(files != null && files.length > 0);
-
- this.expectedFiles = expectedFiles;
- this.optimizedDir = optimizedDir;
- String path = files[0].getAbsolutePath();
- for (int i = 1; i < files.length; i++) {
- path += File.pathSeparator + files[i].getAbsolutePath();
- }
- this.path = path;
- }
- }
+ private File srcDir;
+ private File dex1;
+ private File dex2;
+ private File jar1;
+ private File jar2;
+ private File optimizedDir;
protected void setUp() throws Exception {
- assertTrue(TMP_DIR.exists() || TMP_DIR.mkdirs());
- assertTrue(DEFAULT_OPTIMIZED_DIR.exists() || DEFAULT_OPTIMIZED_DIR.mkdirs());
- assertTrue(INIT1_OPTIMIZED_DIR.exists() || INIT1_OPTIMIZED_DIR.mkdirs());
- assertTrue(INIT2_OPTIMIZED_DIR.exists() || INIT2_OPTIMIZED_DIR.mkdirs());
+ srcDir = File.createTempFile("src", "");
+ assertTrue(srcDir.delete());
+ assertTrue(srcDir.mkdirs());
- ClassLoader cl = DexClassLoaderTest.class.getClassLoader();
- copyResource(cl, JAR_NAME, JAR_FILE);
- copyResource(cl, DEX_NAME, DEX_FILE);
- copyResource(cl, JAR2_NAME, JAR2_FILE);
- copyResource(cl, DEX2_NAME, DEX2_FILE);
+ dex1 = new File(srcDir, "loading-test.dex");
+ dex2 = new File(srcDir, "loading-test2.dex");
+ jar1 = new File(srcDir, "loading-test.jar");
+ jar2 = new File(srcDir, "loading-test2.jar");
+
+ copyResource("loading-test.dex", dex1);
+ copyResource("loading-test2.dex", dex2);
+ copyResource("loading-test.jar", jar1);
+ copyResource("loading-test2.jar", jar2);
+
+ optimizedDir = File.createTempFile("optimized", "");
+ assertTrue(optimizedDir.delete());
+ assertTrue(optimizedDir.mkdirs());
}
protected void tearDown() {
- cleanUpDir(DEFAULT_OPTIMIZED_DIR);
- cleanUpDir(INIT1_OPTIMIZED_DIR);
- cleanUpDir(INIT2_OPTIMIZED_DIR);
+ cleanUpDir(srcDir);
+ cleanUpDir(optimizedDir);
}
- private void cleanUpDir(File dir) {
+ private static void cleanUpDir(File dir) {
if (!dir.isDirectory()) {
return;
}
@@ -127,54 +76,85 @@
/**
* Copy a resource in the package directory to the indicated
- * target file, but only if the target file doesn't exist.
+ * target file.
*/
- private static void copyResource(ClassLoader loader, String resourceName,
+ private static void copyResource(String resourceName,
File destination) throws IOException {
- if (destination.exists()) {
- return;
+ ClassLoader loader = DexClassLoaderTest.class.getClassLoader();
+ assertFalse(destination.exists());
+ InputStream in = loader.getResourceAsStream(PACKAGE_PATH + resourceName);
+ if (in == null) {
+ throw new IllegalStateException("Resource not found: " + PACKAGE_PATH + resourceName);
}
- InputStream in =
- loader.getResourceAsStream(PACKAGE_PATH + resourceName);
- FileOutputStream out = new FileOutputStream(destination);
- Streams.copy(in, out);
- in.close();
- out.close();
+ try (FileOutputStream out = new FileOutputStream(destination)) {
+ Streams.copy(in, out);
+ } finally {
+ in.close();
+ }
}
+ static final FilenameFilter DEX_FILE_NAME_FILTER = new FilenameFilter() {
+ @Override
+ public boolean accept(File file, String s) {
+ return s.endsWith(".dex");
+ }
+ };
+
/**
- * Helper to construct an instance to test.
+ * Helper to construct a DexClassLoader instance to test.
*
- * @param config how to configure the classpath
+ * @param files The .dex or .jar files to use for the class path.
*/
- private static DexClassLoader createInstance(Configuration config) {
- return new DexClassLoader(
- config.path, config.optimizedDir.getAbsolutePath(), null,
+ private ClassLoader createLoader(File... files) {
+ assertNotNull(files);
+ assertTrue(files.length > 0);
+ String path = files[0].getAbsolutePath();
+ for (int i = 1; i < files.length; i++) {
+ path += File.pathSeparator + files[i].getAbsolutePath();
+ }
+ return new DexClassLoader(path, optimizedDir.getAbsolutePath(), null,
ClassLoader.getSystemClassLoader());
}
/**
- * Helper to construct an instance to test, using the jar file as
- * the source, and call a named no-argument static method on a
- * named class.
+ * Helper to construct a new DexClassLoader instance to test, using the
+ * given files as the class path, and call a named no-argument static
+ * method on a named class.
*
- * @param config how to configure the classpath
+ * @param className The name of the class of the method to call.
+ * @param methodName The name of the method to call.
+ * @param files The .dex or .jar files to use for the class path.
*/
- public static Object createInstanceAndCallStaticMethod(
- Configuration config, String className, String methodName)
- throws ClassNotFoundException, NoSuchMethodException,
- IllegalAccessException, InvocationTargetException {
- DexClassLoader dcl = createInstance(config);
- Class c = dcl.loadClass(className);
+ public Object createLoaderAndCallMethod(
+ String className, String methodName, File... files)
+ throws ReflectiveOperationException {
+ ClassLoader cl = createLoader(files);
+ Class c = cl.loadClass(className);
Method m = c.getMethod(methodName, (Class[]) null);
return m.invoke(null, (Object[]) null);
}
- /*
- * Tests that are parametric with respect to whether to use a jar
- * file or a dex file as the source of the code
+ /**
+ * Helper to construct a new DexClassLoader instance to test, using the
+ * given files as the class path, and read the contents of the named
+ * resource as a String.
+ *
+ * @param resourceName The name of the resource to get.
+ * @param files The .dex or .jar files to use for the class path.
*/
+ private String createLoaderAndGetResource(String resourceName, File... files) throws Exception {
+ ClassLoader cl = createLoader(files);
+ InputStream in = cl.getResourceAsStream(resourceName);
+ if (in == null) {
+ throw new IllegalStateException("Resource not found: " + resourceName);
+ }
+
+ byte[] contents = Streams.readFully(in);
+ return new String(contents, "UTF-8");
+ }
+
+ // ONE_JAR
/**
* Just a trivial test of construction. This one merely makes
@@ -182,23 +162,19 @@
* to verify anything about the constructed instance, other than
* checking for the existence of optimized dex files.
*/
- private static void test_init(Configuration config) {
- createInstance(config);
-
- int expectedFiles = config.expectedFiles;
- int actualFiles = config.optimizedDir.listFiles().length;
-
- assertEquals(expectedFiles, actualFiles);
+ public void test_oneJar_init() throws Exception {
+ ClassLoader cl = createLoader(jar1);
+ File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+ assertNotNull(files);
+ assertEquals(1, files.length);
}
/**
* Check that a class in the jar/dex file may be used successfully. In this
* case, a trivial static method is called.
*/
- private static void test_simpleUse(Configuration config) throws Exception {
- String result = (String)
- createInstanceAndCallStaticMethod(config, "test.Test1", "test");
-
+ public void test_oneJar_simpleUse() throws Exception {
+ String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1);
assertSame("blort", result);
}
@@ -207,312 +183,214 @@
* that lives inside the loading-test dex/jar file.
*/
- private static void test_constructor(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_constructor");
- }
-
- private static void test_callStaticMethod(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_callStaticMethod");
- }
-
- private static void test_getStaticVariable(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_getStaticVariable");
- }
-
- private static void test_callInstanceMethod(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_callInstanceMethod");
- }
-
- private static void test_getInstanceVariable(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_getInstanceVariable");
- }
-
- private static void test_diff_constructor(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_diff_constructor");
- }
-
- private static void test_diff_callStaticMethod(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_diff_callStaticMethod");
- }
-
- private static void test_diff_getStaticVariable(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_diff_getStaticVariable");
- }
-
- private static void test_diff_callInstanceMethod(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_diff_callInstanceMethod");
- }
-
- private static void test_diff_getInstanceVariable(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_diff_getInstanceVariable");
- }
-
- /*
- * These methods are all essentially just calls to the
- * parametrically-defined tests above.
- */
-
- // ONE_JAR
-
- public void test_oneJar_init() throws Exception {
- test_init(Configuration.ONE_JAR_INIT);
- }
-
- public void test_oneJar_simpleUse() throws Exception {
- test_simpleUse(Configuration.ONE_JAR);
- }
-
public void test_oneJar_constructor() throws Exception {
- test_constructor(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1);
}
public void test_oneJar_callStaticMethod() throws Exception {
- test_callStaticMethod(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1);
}
public void test_oneJar_getStaticVariable() throws Exception {
- test_getStaticVariable(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1);
}
public void test_oneJar_callInstanceMethod() throws Exception {
- test_callInstanceMethod(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1);
}
public void test_oneJar_getInstanceVariable() throws Exception {
- test_getInstanceVariable(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1);
}
// ONE_DEX
public void test_oneDex_init() throws Exception {
- test_init(Configuration.ONE_DEX_INIT);
+ ClassLoader cl = createLoader(dex1);
+ File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+ assertNotNull(files);
+ assertEquals(1, files.length);
}
public void test_oneDex_simpleUse() throws Exception {
- test_simpleUse(Configuration.ONE_DEX);
+ String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1);
+ assertSame("blort", result);
}
public void test_oneDex_constructor() throws Exception {
- test_constructor(Configuration.ONE_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1);
}
public void test_oneDex_callStaticMethod() throws Exception {
- test_callStaticMethod(Configuration.ONE_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1);
}
public void test_oneDex_getStaticVariable() throws Exception {
- test_getStaticVariable(Configuration.ONE_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1);
}
public void test_oneDex_callInstanceMethod() throws Exception {
- test_callInstanceMethod(Configuration.ONE_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1);
}
public void test_oneDex_getInstanceVariable() throws Exception {
- test_getInstanceVariable(Configuration.ONE_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1);
}
// TWO_JAR
public void test_twoJar_init() throws Exception {
- test_init(Configuration.TWO_JAR_INIT);
+ ClassLoader cl = createLoader(jar1, jar2);
+ File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+ assertNotNull(files);
+ assertEquals(2, files.length);
}
public void test_twoJar_simpleUse() throws Exception {
- test_simpleUse(Configuration.TWO_JAR);
+ String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1, jar2);
+ assertSame("blort", result);
}
public void test_twoJar_constructor() throws Exception {
- test_constructor(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1, jar2);
}
public void test_twoJar_callStaticMethod() throws Exception {
- test_callStaticMethod(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1, jar2);
}
public void test_twoJar_getStaticVariable() throws Exception {
- test_getStaticVariable(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1, jar2);
}
public void test_twoJar_callInstanceMethod() throws Exception {
- test_callInstanceMethod(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1, jar2);
}
public void test_twoJar_getInstanceVariable() throws Exception {
- test_getInstanceVariable(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1, jar2);
}
- public static void test_twoJar_diff_constructor() throws Exception {
- test_diff_constructor(Configuration.TWO_JAR);
+ public void test_twoJar_diff_constructor() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", jar1, jar2);
}
- public static void test_twoJar_diff_callStaticMethod() throws Exception {
- test_diff_callStaticMethod(Configuration.TWO_JAR);
+ public void test_twoJar_diff_callStaticMethod() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", jar1, jar2);
}
- public static void test_twoJar_diff_getStaticVariable() throws Exception {
- test_diff_getStaticVariable(Configuration.TWO_JAR);
+ public void test_twoJar_diff_getStaticVariable() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", jar1, jar2);
}
- public static void test_twoJar_diff_callInstanceMethod()
- throws Exception {
- test_diff_callInstanceMethod(Configuration.TWO_JAR);
+ public void test_twoJar_diff_callInstanceMethod() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", jar1, jar2);
}
- public static void test_twoJar_diff_getInstanceVariable()
- throws Exception {
- test_diff_getInstanceVariable(Configuration.TWO_JAR);
+ public void test_twoJar_diff_getInstanceVariable() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", jar1, jar2);
}
// TWO_DEX
public void test_twoDex_init() throws Exception {
- test_init(Configuration.TWO_DEX_INIT);
+ ClassLoader cl = createLoader(dex1, dex2);
+ File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+ assertNotNull(files);
+ assertEquals(2, files.length);
}
public void test_twoDex_simpleUse() throws Exception {
- test_simpleUse(Configuration.TWO_DEX);
+ String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1, dex2);
+ assertSame("blort", result);
}
public void test_twoDex_constructor() throws Exception {
- test_constructor(Configuration.TWO_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1, dex2);
}
public void test_twoDex_callStaticMethod() throws Exception {
- test_callStaticMethod(Configuration.TWO_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1, dex2);
}
public void test_twoDex_getStaticVariable() throws Exception {
- test_getStaticVariable(Configuration.TWO_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1, dex2);
}
public void test_twoDex_callInstanceMethod() throws Exception {
- test_callInstanceMethod(Configuration.TWO_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1, dex2);
}
public void test_twoDex_getInstanceVariable() throws Exception {
- test_getInstanceVariable(Configuration.TWO_DEX);
+ createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1, dex2);
}
- public static void test_twoDex_diff_constructor() throws Exception {
- test_diff_constructor(Configuration.TWO_DEX);
+ public void test_twoDex_diff_constructor() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", dex1, dex2);
}
- public static void test_twoDex_diff_callStaticMethod() throws Exception {
- test_diff_callStaticMethod(Configuration.TWO_DEX);
+ public void test_twoDex_diff_callStaticMethod() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", dex1, dex2);
}
- public static void test_twoDex_diff_getStaticVariable() throws Exception {
- test_diff_getStaticVariable(Configuration.TWO_DEX);
+ public void test_twoDex_diff_getStaticVariable() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", dex1, dex2);
}
- public static void test_twoDex_diff_callInstanceMethod()
- throws Exception {
- test_diff_callInstanceMethod(Configuration.TWO_DEX);
+ public void test_twoDex_diff_callInstanceMethod() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", dex1, dex2);
}
- public static void test_twoDex_diff_getInstanceVariable()
- throws Exception {
- test_diff_getInstanceVariable(Configuration.TWO_DEX);
+ public void test_twoDex_diff_getInstanceVariable() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", dex1, dex2);
}
/*
* Tests specifically for resource-related functionality. Since
* raw dex files don't contain resources, these test only work
- * with jar files. The first couple methods here are helpers,
- * and they are followed by the tests per se.
+ * with jar files.
*/
/**
- * Check that a given resource (by name) is retrievable and contains
- * the given expected contents.
- */
- private static void test_directGetResourceAsStream(Configuration config,
- String resourceName, String expectedContents)
- throws Exception {
- DexClassLoader dcl = createInstance(config);
- InputStream in = dcl.getResourceAsStream(resourceName);
- byte[] contents = Streams.readFully(in);
- String s = new String(contents, "UTF-8");
-
- assertEquals(expectedContents, s);
- }
-
- /**
* Check that a resource in the jar file is retrievable and contains
* the expected contents.
*/
- private static void test_directGetResourceAsStream(Configuration config)
- throws Exception {
- test_directGetResourceAsStream(
- config, "test/Resource1.txt", "Muffins are tasty!\n");
+ public void test_oneJar_directGetResourceAsStream() throws Exception {
+ String result = createLoaderAndGetResource("test/Resource1.txt", jar1);
+ assertEquals("Muffins are tasty!\n", result);
}
/**
* Check that a resource in the jar file can be retrieved from
* a class within that jar file.
*/
- private static void test_getResourceAsStream(Configuration config)
- throws Exception {
- createInstanceAndCallStaticMethod(
- config, "test.TestMethods", "test_getResourceAsStream");
- }
-
- public void test_oneJar_directGetResourceAsStream() throws Exception {
- test_directGetResourceAsStream(Configuration.ONE_JAR);
- }
-
public void test_oneJar_getResourceAsStream() throws Exception {
- test_getResourceAsStream(Configuration.ONE_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1);
}
public void test_twoJar_directGetResourceAsStream() throws Exception {
- test_directGetResourceAsStream(Configuration.TWO_JAR);
+ String result = createLoaderAndGetResource("test/Resource1.txt", jar1, jar2);
+ assertEquals("Muffins are tasty!\n", result);
}
public void test_twoJar_getResourceAsStream() throws Exception {
- test_getResourceAsStream(Configuration.TWO_JAR);
+ createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1, jar2);
}
/**
* Check that a resource in the second jar file is retrievable and
* contains the expected contents.
*/
- public void test_twoJar_diff_directGetResourceAsStream()
- throws Exception {
- test_directGetResourceAsStream(
- Configuration.TWO_JAR, "test2/Resource2.txt",
- "Who doesn't like a good biscuit?\n");
+ public void test_twoJar_diff_directGetResourceAsStream() throws Exception {
+ String result = createLoaderAndGetResource("test2/Resource2.txt", jar1, jar2);
+ assertEquals("Who doesn't like a good biscuit?\n", result);
}
/**
* Check that a resource in a jar file can be retrieved from
* a class within the other jar file.
*/
- public void test_twoJar_diff_getResourceAsStream()
- throws Exception {
- createInstanceAndCallStaticMethod(
- Configuration.TWO_JAR, "test.TestMethods",
- "test_diff_getResourceAsStream");
+ public void test_twoJar_diff_getResourceAsStream() throws Exception {
+ createLoaderAndCallMethod("test.TestMethods", "test_diff_getResourceAsStream", jar1, jar2);
}
}
diff --git a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
index 9e6d8d7..31e8fc7 100644
--- a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
@@ -17,9 +17,12 @@
package libcore.dalvik.system;
import dalvik.system.PathClassLoader;
+import java.lang.reflect.Method;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import libcore.io.Streams;
import junit.framework.TestCase;
public final class PathClassLoaderTest extends TestCase {
@@ -52,6 +55,26 @@
return result;
}
+ public void testAppUseOfPathClassLoader() throws Exception {
+ // Extract loading-test.jar from the resource.
+ ClassLoader pcl = PathClassLoaderTest.class.getClassLoader();
+ File jar = File.createTempFile("loading-test", ".jar");
+ try (InputStream in = pcl.getResourceAsStream("dalvik/system/loading-test.jar");
+ FileOutputStream out = new FileOutputStream(jar)) {
+ Streams.copy(in, out);
+ }
+
+ // Execute code from the jar file using a PathClassLoader.
+ PathClassLoader cl = new PathClassLoader(jar.getPath(), pcl);
+ Class c = cl.loadClass("test.Test1");
+ Method m = c.getMethod("test", (Class[]) null);
+ String result = (String) m.invoke(null, (Object[]) null);
+ assertSame("blort", result);
+
+ // Clean up the extracted jar file.
+ assertTrue(jar.delete());
+ }
+
@Override protected void setUp() throws Exception {
super.setUp();
}
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index dee5bdd..93b06c8 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -260,12 +260,14 @@
while(rt.freeMemory() < beforeTest * 2/3) {
vec.add(new StringBuffer(1000));
}
- long beforeGC = rt.freeMemory();
+ long beforeGC = rt.totalMemory() - rt.freeMemory();
+ vec = null;
System.gc();
- long afterGC = rt.freeMemory();
+ System.runFinalization();
+ long afterGC = rt.totalMemory() - rt.freeMemory();
assertTrue("memory was not released after calling System.gc()." +
"before gc: " + beforeGC + "; after gc: " + afterGC,
- beforeGC < afterGC);
+ beforeGC > afterGC);
}
public void test_getenv() {
diff --git a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
index e874a1b..4fa6e0c 100644
--- a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
+++ b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
@@ -105,4 +105,15 @@
assertEquals(1, cb.position());
assertEquals('\u2603', cb.get(0));
}
+
+ public void testBufferWithNonZeroOffset() {
+ CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
+ CharBuffer cb = CharBuffer.allocate(128);
+ cb.position(42);
+ CharBuffer out = cb.slice();
+ CoderResult cr = decoder.decode(
+ ByteBuffer.wrap(new byte[] { 'h', 'e', 'l', 'l', 'o'}), out, false);
+ assertTrue(cr.isUnderflow());
+ assertEquals(5, out.position());
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 0be558e..9cb780a 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -547,6 +547,15 @@
}
}
+ public void testProvider_removeProvider_Success() throws Exception {
+ MockProvider provider = new MockProvider("MockProvider");
+ assertNull(Security.getProvider(provider.getName()));
+ Security.addProvider(provider);
+ assertNotNull(Security.getProvider(provider.getName()));
+ Security.removeProvider(provider.getName());
+ assertNull(Security.getProvider(provider.getName()));
+ }
+
public static class MyCertStoreSpi extends CertStoreSpi {
public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException {
super(params);
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index f28446c..6129e1e 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -393,9 +393,14 @@
return data;
}
- // http://code.google.com/p/android/issues/detail?id=18566
- // http://b/5038554
- public void test18566() throws Exception {
+ /**
+ * This should actually fail because the ASN.1 encoding is incorrect. It is
+ * missing the NULL in the AlgorithmIdentifier field.
+ * <p>
+ * http://code.google.com/p/android/issues/detail?id=18566 <br/>
+ * http://b/5038554
+ */
+ public void test18566_AlgorithmOid_MissingNull_Failure() throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(PK_BYTES);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pk = keyFactory.generatePublic(keySpec);
@@ -403,7 +408,7 @@
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pk);
sig.update(CONTENT);
- assertTrue(sig.verify(SIGNATURE));
+ assertFalse(sig.verify(SIGNATURE));
}
/*
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
index 3e0aeba..b1d37f3 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
@@ -86,4 +86,34 @@
assertEquals("$", dfs.getCurrencySymbol());
assertEquals(null, dfs.getInternationalCurrencySymbol());
}
+
+ // https://code.google.com/p/android/issues/detail?id=170718
+ public void testSerializationOfMultiCharNegativeAndPercentage() throws Exception {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+ assertTrue(dfs.getMinusSignString().length() > 1);
+ assertTrue(dfs.getPercentString().length() > 1);
+
+ // Serialize...
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new ObjectOutputStream(out).writeObject(dfs);
+ byte[] bytes = out.toByteArray();
+
+ // Deserialize...
+ ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ DecimalFormatSymbols deserializedDfs = (DecimalFormatSymbols) in.readObject();
+ assertEquals(-1, in.read());
+
+ assertEquals(dfs.getMinusSignString(), deserializedDfs.getMinusSignString());
+ assertEquals(dfs.getPercentString(), deserializedDfs.getPercentString());
+ }
+
+ // http://b/18785260
+ public void testMultiCharMinusSignAndPercentage() {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+ assertTrue(dfs.getMinusSignString().length() > 1);
+ assertTrue(dfs.getPercentString().length() > 1);
+
+ assertEquals('%', dfs.getPercent());
+ assertEquals('-', dfs.getMinusSign());
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
index ad084e1..22e6795 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
@@ -478,17 +478,10 @@
} catch (IllegalArgumentException expected) {
}
- if (StandardNames.IS_RI) {
- try {
- sig.verify(signature, signature.length, 0);
- fail();
- } catch (SignatureException expected) {
- }
- } else {
- // Calling Signature.verify a second time should not throw
- // http://code.google.com/p/android/issues/detail?id=34933
- boolean verified = sig.verify(signature, signature.length, 0);
- assertFalse(verified);
+ try {
+ sig.verify(signature, signature.length, 0);
+ fail();
+ } catch (SignatureException expected) {
}
try {
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 9aab942..793c409 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -180,7 +180,6 @@
provide("Cipher", "DES");
provide("Cipher", "DESede");
provide("Cipher", "DESedeWrap");
- provide("Cipher", "GCM");
provide("Cipher", "PBEWithMD5AndDES");
provide("Cipher", "PBEWithMD5AndTripleDES");
provide("Cipher", "PBEWithSHA1AndDESede");
@@ -312,25 +311,29 @@
// Only available with the SunPKCS11-NSS provider,
// which seems to be enabled in OpenJDK 6 but not Oracle Java 6
if (Security.getProvider("SunPKCS11-NSS") != null) {
- provide("AlgorithmParameters", "EC");
provide("Cipher", "AES/CBC/NOPADDING");
provide("Cipher", "DES/CBC/NOPADDING");
provide("Cipher", "DESEDE/CBC/NOPADDING");
provide("Cipher", "RSA/ECB/PKCS1PADDING");
provide("KeyAgreement", "DH");
- provide("KeyAgreement", "ECDH");
provide("KeyFactory", "DH");
- provide("KeyFactory", "EC");
provide("KeyPairGenerator", "DH");
- provide("KeyPairGenerator", "EC");
provide("KeyStore", "PKCS11");
provide("MessageDigest", "SHA1");
provide("SecretKeyFactory", "AES");
provide("SecretKeyFactory", "ARCFOUR");
provide("SecureRandom", "PKCS11");
provide("Signature", "DSA");
- provide("Signature", "NONEWITHECDSA");
provide("Signature", "RAWDSA");
+ }
+
+ if (Security.getProvider("SunPKCS11-NSS") != null ||
+ Security.getProvider("SunEC") != null) {
+ provide("AlgorithmParameters", "EC");
+ provide("KeyAgreement", "ECDH");
+ provide("KeyFactory", "EC");
+ provide("KeyPairGenerator", "EC");
+ provide("Signature", "NONEWITHECDSA");
provide("Signature", "SHA1WITHECDSA");
provide("Signature", "SHA224WITHECDSA");
provide("Signature", "SHA256WITHECDSA");
@@ -479,6 +482,7 @@
provide("Cipher", "AES/ECB/NOPADDING");
provide("Cipher", "AES/ECB/PKCS5PADDING");
provide("Cipher", "AES/ECB/PKCS7PADDING");
+ provide("Cipher", "AES/GCM/NOPADDING");
provide("Cipher", "AES/OFB/NOPADDING");
provide("Cipher", "AES/OFB/PKCS5PADDING");
provide("Cipher", "AES/OFB/PKCS7PADDING");