Merge "Update java.util.jar to openJdk8u60"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index cda2d47..33b127c 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -171,8 +171,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, dalvik/test-rules/src/main test-rules/src/main)
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_MODULE := core-test-rules
-LOCAL_JAVA_LIBRARIES := core-all core-junit
-LOCAL_STATIC_JAVA_LIBRARIES := junit4-target
+LOCAL_JAVA_LIBRARIES := core-all
+LOCAL_STATIC_JAVA_LIBRARIES := junit
include $(BUILD_STATIC_JAVA_LIBRARY)
# Build libcore test rules for host
@@ -206,7 +206,7 @@
LOCAL_SRC_FILES := $(test_src_files)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp core-junit junit4-target bouncycastle mockito-target
+LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp junit bouncycastle mockito-target
LOCAL_STATIC_JAVA_LIBRARIES := \
core-test-rules \
core-tests-support \
@@ -227,7 +227,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit junit4-target bouncycastle
+LOCAL_JAVA_LIBRARIES := core-oj core-libart junit bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-bcpkix bouncycastle-ocsp
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := core-tests-support
@@ -241,7 +241,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under, jsr166-tests)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit junit4-target
+LOCAL_JAVA_LIBRARIES := core-oj core-libart junit
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := jsr166-tests
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
index 22d0d26..c48c224 100644
--- a/benchmarks/Android.mk
+++ b/benchmarks/Android.mk
@@ -28,7 +28,7 @@
core-oj \
core-libart \
conscrypt \
- core-junit \
+ legacy-test \
bouncycastle \
framework
LOCAL_MODULE_TAGS := tests
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectInputStream2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectInputStream2Test.java
index e81224a..af5fce5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectInputStream2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectInputStream2Test.java
@@ -17,10 +17,8 @@
package org.apache.harmony.tests.java.io;
-import dalvik.system.DexFile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
@@ -29,9 +27,6 @@
import java.io.ObjectStreamClass;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import junit.framework.TestCase;
@@ -215,54 +210,4 @@
// Excpected
}
}
-
- // http://b/29721023
- public void test_sameName() throws Exception {
- // Load class from dex, it's not possible to create a class with same-named
- // fields in java (but it's allowed in dex).
- File sameFieldNames = File.createTempFile("sameFieldNames", ".dex");
- InputStream dexIs = this.getClass().getClassLoader().
- getResourceAsStream("tests/api/java/io/sameFieldNames.dex");
- assertNotNull(dexIs);
-
- Class<?> clazz = null;
-
- // Get the class object
- try {
- Files.copy(dexIs, sameFieldNames.toPath(), StandardCopyOption.REPLACE_EXISTING);
- DexFile dexFile = new DexFile(sameFieldNames);
- clazz = dexFile.loadClass("sameFieldNames", getClass().getClassLoader());
- dexFile.close();
- } finally {
- if (sameFieldNames.exists()) {
- sameFieldNames.delete();
- }
- }
-
- // Create class instance, fill it with content
- Object o1 = clazz.getConstructor().newInstance();
- int v = 123;
- for(Field f : clazz.getFields()) {
- if (f.getType() == Integer.class) {
- f.set(o1, new Integer(v++));
- } else if (f.getType() == Long.class) {
- f.set(o1, new Long(v++));
- }
- }
-
- // Serialize and deserialize
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(o1);
- oos.close();
- ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
- baos.toByteArray()));
- Object o2 = ois.readObject();
- ois.close();
-
- // Compare content
- for(Field f : clazz.getFields()) {
- assertEquals(f.get(o1), f.get(o2));
- }
- }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
index 6253b6b..bebeb6e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
@@ -17,23 +17,17 @@
package org.apache.harmony.tests.java.io;
-import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
import java.io.Externalizable;
-import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.Serializable;
-import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
import junit.framework.TestCase;
public class ObjectStreamClassTest extends TestCase {
@@ -325,27 +319,4 @@
hasStaticInitializer.invoke(null, NoClinitChildWithNoClinitParent.class,
true /* checkSuperclass */));
}
-
- // http://b/29721023
- public void testClassWithSameFieldName() throws Exception {
- // Load class from dex, it's not possible to create a class with same-named
- // fields in java (but it's allowed in dex).
- File sameFieldNames = File.createTempFile("sameFieldNames", ".dex");
- InputStream dexIs = this.getClass().getClassLoader().
- getResourceAsStream("tests/api/java/io/sameFieldNames.dex");
- assertNotNull(dexIs);
-
- try {
- Files.copy(dexIs, sameFieldNames.toPath(), StandardCopyOption.REPLACE_EXISTING);
- DexFile dexFile = new DexFile(sameFieldNames);
- Class<?> clazz = dexFile.loadClass("sameFieldNames", getClass().getClassLoader());
- ObjectStreamClass osc = ObjectStreamClass.lookup(clazz);
- assertEquals(4, osc.getFields().length);
- dexFile.close();
- } finally {
- if (sameFieldNames.exists()) {
- sameFieldNames.delete();
- }
- }
- }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index 1cb6808..7523752 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -31,11 +31,15 @@
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
+import libcore.io.Libcore;
import libcore.junit.junit3.TestCaseWithRules;
import libcore.junit.util.ResourceLeakageDetector;
import org.junit.Rule;
import org.junit.rules.TestRule;
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IP_MULTICAST_ALL;
+
public class DatagramSocketTest extends TestCaseWithRules {
@Rule
public TestRule guardRule = ResourceLeakageDetector.getRule();
@@ -97,8 +101,14 @@
/**
* java.net.DatagramSocket#DatagramSocket()
*/
- public void test_Constructor() throws SocketException {
- new DatagramSocket().close();
+ public void test_Constructor() throws Exception {
+ try (DatagramSocket ds = new DatagramSocket()) {
+ // Datagram sockets bound to the wildcard INADDR_ANY address should by default only
+ // receive messages from groups they explicitly joined.
+ boolean multicastAllEnabled = Libcore.os.getsockoptInt(ds.getFileDescriptor$(),
+ IPPROTO_IP, IP_MULTICAST_ALL) == 1;
+ assertFalse(multicastAllEnabled);
+ }
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
index 302b505..261975a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/WeakHashMapTest.java
@@ -310,14 +310,20 @@
long startTime = System.currentTimeMillis();
// We use a busy wait loop here since we cannot know when the ReferenceQueue
// daemon will enqueue the cleared references on their internal reference
- // queues. The current timeout is 5 seconds.
+ // queues.
+ // The timeout after which the reference should be cleared. This test used to
+ // be flaky when it was set to 5 seconds. Daemons.MAX_FINALIZE_NANOS is
+ // currently 10 seconds so that seems like the correct value.
+ // We allow an extra 500msec buffer to minimize races between finalizer,
+ // keySet.size() evaluation and time check.
+ long timeout = 10000 + 500;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
} while (keySet.size() != 99 &&
- System.currentTimeMillis() - startTime < 5000);
+ System.currentTimeMillis() - startTime < timeout);
assertEquals("Incorrect number of keys returned after gc,", 99, keySet.size());
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
index bb2265f..74c3a7f 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
@@ -25,6 +25,7 @@
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.util.Base64;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.KeyManager;
@@ -39,7 +40,6 @@
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import junit.framework.TestCase;
-import libcore.io.Base64;
import org.apache.harmony.xnet.tests.support.mySSLSession;
/**
@@ -535,7 +535,7 @@
* for the result.
*/
private KeyManager[] getKeyManagers(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
index 5a0cf6f..117a1a0 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLServerSocketTest.java
@@ -18,8 +18,6 @@
import junit.framework.TestCase;
-import libcore.io.Base64;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -27,6 +25,7 @@
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -391,7 +390,7 @@
*/
private KeyManager[] getKeyManagers() throws Exception {
String keys = (useBKS ? SERVER_KEYS_BKS : SERVER_KEYS_JKS);
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
index 018de8c..fde1ff8 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSessionTest.java
@@ -26,6 +26,7 @@
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.ExtendedSSLSession;
import javax.net.ssl.KeyManager;
@@ -42,7 +43,6 @@
import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
import junit.framework.TestCase;
-import libcore.io.Base64;
import libcore.java.security.StandardNames;
public class SSLSessionTest extends TestCase {
@@ -643,7 +643,7 @@
* for the result.
*/
private KeyStore getKeyStore(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
index a791a77..5712a48 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLSocketTest.java
@@ -24,6 +24,7 @@
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Base64;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.KeyManager;
@@ -35,7 +36,6 @@
import javax.net.ssl.TrustManager;
import javax.security.cert.X509Certificate;
import junit.framework.TestCase;
-import libcore.io.Base64;
import libcore.java.security.StandardNames;
import org.apache.harmony.tests.javax.net.ssl.HandshakeCompletedEventTest.TestTrustManager;
@@ -587,7 +587,7 @@
* for the result.
*/
private KeyManager[] getKeyManagers(String keys) throws Exception {
- byte[] bytes = Base64.decode(keys.getBytes());
+ byte[] bytes = Base64.getDecoder().decode(keys.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
diff --git a/libart/src/main/java/dalvik/system/ClassExt.java b/libart/src/main/java/dalvik/system/ClassExt.java
index a23529b..131124e 100644
--- a/libart/src/main/java/dalvik/system/ClassExt.java
+++ b/libart/src/main/java/dalvik/system/ClassExt.java
@@ -27,8 +27,44 @@
*/
public final class ClassExt {
/**
+ * An array of all obsolete DexCache objects that are needed for obsolete methods.
+ *
+ * These entries are associated with the obsolete ArtMethod pointers at the same indexes in the
+ * obsoleteMethods array.
+ *
+ * This field has native components and is a logical part of the 'Class' type.
+ */
+ private Object[] obsoleteDexCaches;
+
+ /**
+ * An array of all native obsolete ArtMethod pointers.
+ *
+ * These are associated with their DexCaches at the same index in the obsoleteDexCaches array.
+ *
+ * This field is actually either an int[] or a long[] depending on size of a pointer.
+ *
+ * This field contains native pointers and is a logical part of the 'Class' type.
+ */
+ private Object obsoleteMethods;
+
+ /**
+ * If set, the original DexCache associated with the related class.
+ *
+ * In this instance 'original' means the dex-cache (and associated dex-file) for this class when
+ * it was first loaded after all non-retransformation capable transformations had been performed
+ * but before any retransformation capable ones had been done.
+ *
+ * Needed in order to implement retransformation of classes.
+ *
+ * This field has native components and is a logical part of the 'Class' type.
+ */
+ private Object originalDexCache;
+
+ /**
* If class verify fails, we must return same error on subsequent tries. We may store either
* the class of the error, or an actual instance of Throwable here.
+ *
+ * This field is a logical part of the 'Class' type.
*/
private Object verifyError;
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 28b2523..96846ca 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -313,6 +313,7 @@
public static final int IPV6_TCLASS = placeholder();
public static final int IPV6_UNICAST_HOPS = placeholder();
public static final int IPV6_V6ONLY = placeholder();
+ /** @hide */ public static final int IP_MULTICAST_ALL = placeholder();
public static final int IP_MULTICAST_IF = placeholder();
public static final int IP_MULTICAST_LOOP = placeholder();
public static final int IP_MULTICAST_TTL = placeholder();
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 02cfa01..91c3197 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -100,7 +100,10 @@
// We search the list for that FinalizerReference (it should be at or near the head),
// and then put it on the queue so that it can be finalized.
for (FinalizerReference<?> r = head; r != null; r = r.next) {
- if (r.referent == sentinel) {
+ // Use getReferent() instead of directly accessing the referent field not to race
+ // with GC reference processing. Can't use get() either because it's overridden to
+ // return the zombie.
+ if (r.getReferent() == sentinel) {
FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
sentinelReference.referent = null;
sentinelReference.zombie = sentinel;
@@ -126,6 +129,7 @@
throw new AssertionError("newly-created live Sentinel not on list!");
}
+ private final native T getReferent();
private native boolean makeCircularListIfUnenqueued();
/**
diff --git a/luni/src/main/java/libcore/io/Base64.java b/luni/src/main/java/libcore/io/Base64.java
deleted file mode 100644
index f22bef4..0000000
--- a/luni/src/main/java/libcore/io/Base64.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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 libcore.io;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-
-/**
- * Perform encoding and decoding of Base64 byte arrays as described in
- * http://www.ietf.org/rfc/rfc2045.txt
- *
- * @deprecated use {@link java.util.Base64} instead
- */
-@Deprecated
-public final class Base64 {
- private static final byte[] BASE_64_ALPHABET = initializeBase64Alphabet();
-
- private static byte[] initializeBase64Alphabet() {
- return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
- .getBytes(StandardCharsets.US_ASCII);
- }
-
- // Bit masks for the 4 output 6-bit values from 3 input bytes.
- private static final int FIRST_OUTPUT_BYTE_MASK = 0x3f << 18;
- private static final int SECOND_OUTPUT_BYTE_MASK = 0x3f << 12;
- private static final int THIRD_OUTPUT_BYTE_MASK = 0x3f << 6;
- private static final int FOURTH_OUTPUT_BYTE_MASK = 0x3f;
-
- private Base64() {}
-
- public static String encode(byte[] in) {
- int len = in.length;
- int outputLen = computeEncodingOutputLen(len);
- byte[] output = new byte[outputLen];
-
- int outputIndex = 0;
- for (int i = 0; i < len; i += 3) {
- // Only a "triplet" if there are there are at least three remaining bytes
- // in the input...
- // Mask with 0xff to avoid signed extension.
- int byteTripletAsInt = in[i] & 0xff;
- if (i + 1 < len) {
- // Add second byte to the triplet.
- byteTripletAsInt <<= 8;
- byteTripletAsInt |= in[i + 1] & 0xff;
- if (i + 2 < len) {
- byteTripletAsInt <<= 8;
- byteTripletAsInt |= in[i + 2] & 0xff;
- } else {
- // Insert 2 zero bits as to make output 18 bits long.
- byteTripletAsInt <<= 2;
- }
- } else {
- // Insert 4 zero bits as to make output 12 bits long.
- byteTripletAsInt <<= 4;
- }
-
- if (i + 2 < len) {
- // The int may have up to 24 non-zero bits.
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & FIRST_OUTPUT_BYTE_MASK) >>> 18];
- }
- if (i + 1 < len) {
- // The int may have up to 18 non-zero bits.
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & SECOND_OUTPUT_BYTE_MASK) >>> 12];
- }
- output[outputIndex++] = BASE_64_ALPHABET[
- (byteTripletAsInt & THIRD_OUTPUT_BYTE_MASK) >>> 6];
- output[outputIndex++] = BASE_64_ALPHABET[
- byteTripletAsInt & FOURTH_OUTPUT_BYTE_MASK];
- }
-
- int inLengthMod3 = len % 3;
- // Add padding as per the spec.
- if (inLengthMod3 > 0) {
- output[outputIndex++] = '=';
- if (inLengthMod3 == 1) {
- output[outputIndex++] = '=';
- }
- }
-
- return new String(output, StandardCharsets.US_ASCII);
- }
-
- private static int computeEncodingOutputLen(int inLength) {
- int inLengthMod3 = inLength % 3;
- int outputLen = (inLength / 3) * 4;
- if (inLengthMod3 == 2) {
- // Need 3 6-bit characters as to express the last 16 bits, plus 1 padding.
- outputLen += 4;
- } else if (inLengthMod3 == 1) {
- // Need 2 6-bit characters as to express the last 8 bits, plus 2 padding.
- outputLen += 4;
- }
- return outputLen;
- }
-
- public static byte[] decode(byte[] in) {
- return decode(in, in.length);
- }
-
- /** Decodes the input from position 0 (inclusive) to len (exclusive). */
- public static byte[] decode(byte[] in, int len) {
- final int inLength = Math.min(in.length, len);
- // Overestimating 3 bytes per each 4 blocks of input (plus a possibly incomplete one).
- ByteArrayOutputStream output = new ByteArrayOutputStream((inLength / 4) * 3 + 3);
- // Position in the input. Use an array so we can pass it to {@code getNextByte}.
- int[] pos = new int[1];
-
- try {
- while (pos[0] < inLength) {
- int byteTripletAsInt = 0;
-
- // j is the index in a 4-tuple of 6-bit characters where are trying to read from the
- // input.
- for (int j = 0; j < 4; j++) {
- byte c = getNextByte(in, pos, inLength);
- if (c == END_OF_INPUT || c == PAD_AS_BYTE) {
- // Padding or end of file...
- switch (j) {
- case 0:
- case 1:
- return (c == END_OF_INPUT) ? output.toByteArray() : null;
- case 2:
- // The input is over with two 6-bit characters: a single byte padded
- // with 4 extra 0's.
-
- if (c == END_OF_INPUT) {
- // Do not consider the block, since padding is not present.
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- // We are at a pad character, consume and look for the second one.
- pos[0]++;
- c = getNextByte(in, pos, inLength);
- if (c == END_OF_INPUT) {
- // Do not consider the block, since padding is not present.
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- if (c == PAD_AS_BYTE) {
- byteTripletAsInt >>= 4;
- output.write(byteTripletAsInt);
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- // Something other than pad and non-alphabet characters, illegal.
- return null;
-
-
- case 3:
- // The input is over with three 6-bit characters: two bytes padded
- // with 2 extra 0's.
- if (c == PAD_AS_BYTE) {
- // Consider the block only if padding is present.
- byteTripletAsInt >>= 2;
- output.write(byteTripletAsInt >> 8);
- output.write(byteTripletAsInt & 0xff);
- }
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- }
- } else {
- byteTripletAsInt <<= 6;
- byteTripletAsInt += (c & 0xff);
- pos[0]++;
- }
- }
- // We have four 6-bit characters: output the corresponding 3 bytes
- output.write(byteTripletAsInt >> 16);
- output.write((byteTripletAsInt >> 8) & 0xff);
- output.write(byteTripletAsInt & 0xff);
- }
- return checkNoTrailingAndReturn(output, in, pos[0], inLength);
- } catch (InvalidBase64ByteException e) {
- return null;
- }
- }
-
- /**
- * On decoding, an illegal character always return null.
- *
- * Using this exception to avoid "if" checks every time.
- */
-
- private static class InvalidBase64ByteException extends Exception { }
-
- /**
- * Obtain the numeric value corresponding to the next relevant byte in the input.
- *
- * Calculates the numeric value (6-bit, 0 <= x <= 63) of the next Base64 encoded byte in
- * {@code in} at or after {@code pos[0]} and before {@code inLength}. Returns
- * {@link #WHITESPACE_AS_BYTE}, {@link #PAD_AS_BYTE}, {@link #END_OF_INPUT} or the 6-bit value.
- * {@code pos[0]} is updated as a side effect of this method.
- */
- private static byte getNextByte(byte[] in, int[] pos, int inLength)
- throws InvalidBase64ByteException {
- // Ignore all whitespace.
- while (pos[0] < inLength) {
- byte c = base64AlphabetToNumericalValue(in[pos[0]]);
- if (c != WHITESPACE_AS_BYTE) {
- return c;
- }
- pos[0]++;
- }
- return END_OF_INPUT;
- }
-
- /**
- * Check that there are no invalid trailing characters (ie, other then whitespace and padding)
- *
- * Returns {@code output} as a byte array in case of success, {@code null} in case of invalid
- * characters.
- */
- private static byte[] checkNoTrailingAndReturn(
- ByteArrayOutputStream output, byte[] in, int i, int inLength)
- throws InvalidBase64ByteException{
- while (i < inLength) {
- byte c = base64AlphabetToNumericalValue(in[i]);
- if (c != WHITESPACE_AS_BYTE && c != PAD_AS_BYTE) {
- return null;
- }
- i++;
- }
- return output.toByteArray();
- }
-
- private static final byte PAD_AS_BYTE = -1;
- private static final byte WHITESPACE_AS_BYTE = -2;
- private static final byte END_OF_INPUT = -3;
- private static byte base64AlphabetToNumericalValue(byte c) throws InvalidBase64ByteException {
- if ('A' <= c && c <= 'Z') {
- return (byte) (c - 'A');
- }
- if ('a' <= c && c <= 'z') {
- return (byte) (c - 'a' + 26);
- }
- if ('0' <= c && c <= '9') {
- return (byte) (c - '0' + 52);
- }
- if (c == '+') {
- return (byte) 62;
- }
- if (c == '/') {
- return (byte) 63;
- }
- if (c == '=') {
- return PAD_AS_BYTE;
- }
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
- return WHITESPACE_AS_BYTE;
- }
- throw new InvalidBase64ByteException();
- }
-}
diff --git a/luni/src/main/java/libcore/io/DropBox.java b/luni/src/main/java/libcore/io/DropBox.java
index cf88106..4180a2a 100644
--- a/luni/src/main/java/libcore/io/DropBox.java
+++ b/luni/src/main/java/libcore/io/DropBox.java
@@ -16,6 +16,8 @@
package libcore.io;
+import java.util.Base64;
+
public final class DropBox {
/**
@@ -54,7 +56,7 @@
private static final class DefaultReporter implements Reporter {
public void addData(String tag, byte[] data, int flags) {
- System.out.println(tag + ": " + Base64.encode(data));
+ System.out.println(tag + ": " + Base64.getEncoder().encodeToString(data));
}
public void addText(String tag, String data) {
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index f5177fd..e5d1930 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -35,7 +35,6 @@
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.PortUnreachableException;
-import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOptions;
import java.net.SocketTimeoutException;
@@ -645,6 +644,29 @@
}
}
+ /**
+ * Wait for some event on a file descriptor, blocks until the event happened or timeout period
+ * passed. See poll(2) and @link{android.system.Os.Poll}.
+ *
+ * @throws SocketException if poll(2) fails.
+ * @throws SocketTimeoutException if the event has not happened before timeout period has passed.
+ */
+ public static void poll(FileDescriptor fd, int events, int timeout)
+ throws SocketException, SocketTimeoutException {
+ StructPollfd[] pollFds = new StructPollfd[]{ new StructPollfd() };
+ pollFds[0].fd = fd;
+ pollFds[0].events = (short) events;
+
+ try {
+ int ret = android.system.Os.poll(pollFds, timeout);
+ if (ret == 0) {
+ throw new SocketTimeoutException("Poll timed out");
+ }
+ } catch (ErrnoException e) {
+ e.rethrowAsSocketException();
+ }
+ }
+
public static InetSocketAddress getLocalInetSocketAddress(FileDescriptor fd) throws SocketException {
try {
return (InetSocketAddress) Libcore.os.getsockname(fd);
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index c53db12..e6559b5 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -37,8 +37,8 @@
* @hide - used to implement TimeZone
*/
public final class ZoneInfoDB {
- private static final TzData DATA =
- new TzData(System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
+ private static final TzData DATA = TzData.loadTzDataWithFallback(
+ System.getenv("ANDROID_DATA") + "/misc/zoneinfo/current/tzdata",
System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata");
public static class TzData {
@@ -83,10 +83,16 @@
}
};
- public TzData(String... paths) {
+ /**
+ * Loads the data at the specified paths in order, returning the first valid one as a
+ * {@link TzData} object. If there is no valid one found a basic fallback instance is created
+ * containing just GMT.
+ */
+ public static TzData loadTzDataWithFallback(String... paths) {
for (String path : paths) {
- if (loadData(path)) {
- return;
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
}
}
@@ -94,10 +100,28 @@
// This is actually implemented in TimeZone itself, so if this is the only time zone
// we report, we won't be asked any more questions.
System.logE("Couldn't find any tzdata!");
- version = "missing";
- zoneTab = "# Emergency fallback data.\n";
- ids = new String[] { "GMT" };
- byteOffsets = rawUtcOffsetsCache = new int[1];
+ return TzData.createFallback();
+ }
+
+ /**
+ * Loads the data at the specified path and returns the {@link TzData} object if it is valid,
+ * otherwise {@code null}.
+ */
+ public static TzData loadTzData(String path) {
+ TzData tzData = new TzData();
+ if (tzData.loadData(path)) {
+ return tzData;
+ }
+ return null;
+ }
+
+ private static TzData createFallback() {
+ TzData tzData = new TzData();
+ tzData.populateFallback();
+ return tzData;
+ }
+
+ private TzData() {
}
/**
@@ -115,6 +139,13 @@
return it;
}
+ private void populateFallback() {
+ version = "missing";
+ zoneTab = "# Emergency fallback data.\n";
+ ids = new String[] { "GMT" };
+ byteOffsets = rawUtcOffsetsCache = new int[1];
+ }
+
private boolean loadData(String path) {
try {
mappedFile = MemoryMappedFile.mmapRO(path);
@@ -125,6 +156,11 @@
readHeader();
return true;
} catch (Exception ex) {
+ try {
+ mappedFile.close();
+ } catch (ErrnoException ignored) {
+ }
+
// Something's wrong with the file.
// Log the problem and return false so we try the next choice.
System.logE("tzdata file \"" + path + "\" was present but invalid!", ex);
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 7334420..a8b2c2f 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -335,6 +335,7 @@
#endif
initConstant(env, c, "IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS);
initConstant(env, c, "IPV6_V6ONLY", IPV6_V6ONLY);
+ initConstant(env, c, "IP_MULTICAST_ALL", IP_MULTICAST_ALL);
initConstant(env, c, "IP_MULTICAST_IF", IP_MULTICAST_IF);
initConstant(env, c, "IP_MULTICAST_LOOP", IP_MULTICAST_LOOP);
initConstant(env, c, "IP_MULTICAST_TTL", IP_MULTICAST_TTL);
diff --git a/luni/src/main/native/java_lang_StringToReal.cpp b/luni/src/main/native/java_lang_StringToReal.cpp
index d1902af..c321702 100644
--- a/luni/src/main/native/java_lang_StringToReal.cpp
+++ b/luni/src/main/native/java_lang_StringToReal.cpp
@@ -286,6 +286,7 @@
free(y);
free(D);
free(D2);
+ y = D = D2 = NULL;
if (e >= 0 && k >= 0)
{
@@ -713,6 +714,7 @@
free(y);
free(D);
free(D2);
+ y = D = D2 = NULL;
if (e >= 0 && k >= 0)
{
diff --git a/luni/src/test/java/libcore/java/nio/BufferTest.java b/luni/src/test/java/libcore/java/nio/BufferTest.java
index 9a2cb12..9063e27 100644
--- a/luni/src/test/java/libcore/java/nio/BufferTest.java
+++ b/luni/src/test/java/libcore/java/nio/BufferTest.java
@@ -1429,4 +1429,41 @@
assertFalse(bigEndian.asFloatBuffer().slice().get() ==
littleEndian.asFloatBuffer().slice().get());
}
+
+ // http://b/32655865
+ public void test_ByteBufferAsXBuffer_ByteOrder_2() {
+ ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
+ byteBuffer.order(ByteOrder.BIG_ENDIAN);
+ // Fill a ByteBuffer with different bytes that make it easy to tell byte ordering issues.
+ for (int i = 0; i < 10; i++) {
+ byteBuffer.put((byte)i);
+ }
+ byteBuffer.rewind();
+
+ // Create BIG_ENDIAN views of the buffer.
+ ShortBuffer sb_be = byteBuffer.asShortBuffer();
+ LongBuffer lb_be = byteBuffer.asLongBuffer();
+ IntBuffer ib_be = byteBuffer.asIntBuffer();
+ DoubleBuffer db_be = byteBuffer.asDoubleBuffer();
+ CharBuffer cb_be = byteBuffer.asCharBuffer();
+ FloatBuffer fb_be = byteBuffer.asFloatBuffer();
+
+ // Change the order of the underlying buffer.
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // Create LITTLE_ENDIAN views of the buffer.
+ ShortBuffer sb_le = byteBuffer.asShortBuffer();
+ LongBuffer lb_le = byteBuffer.asLongBuffer();
+ IntBuffer ib_le = byteBuffer.asIntBuffer();
+ DoubleBuffer db_le = byteBuffer.asDoubleBuffer();
+ CharBuffer cb_le = byteBuffer.asCharBuffer();
+ FloatBuffer fb_le = byteBuffer.asFloatBuffer();
+
+ assertFalse(sb_be.get() == sb_le.get());
+ assertFalse(lb_be.get() == lb_le.get());
+ assertFalse(ib_be.get() == ib_le.get());
+ assertFalse(db_be.get() == db_le.get());
+ assertFalse(cb_be.get() == cb_le.get());
+ assertFalse(fb_be.get() == fb_le.get());
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
index 52146ee..ae45c0d 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
@@ -18,7 +18,6 @@
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -28,6 +27,7 @@
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
@@ -36,6 +36,10 @@
import java.util.ArrayList;
import java.util.Enumeration;
+import libcore.io.IoBridge;
+
+import static android.system.OsConstants.POLLIN;
+
/**
* Tests associated with multicast behavior of DatagramChannel.
* These tests require IPv6 multicasting enabled network.
@@ -774,6 +778,7 @@
// Send a message. It should be received.
String msg1 = "Hello1";
sendMessage(sendingChannel, msg1, groupSocketAddress);
+ IoBridge.poll(receivingChannel.socket().getFileDescriptor$(), POLLIN, 1000);
InetSocketAddress sourceAddress1 = (InetSocketAddress) receivingChannel.receive(receiveBuffer);
assertEquals(sourceAddress1, sendingAddress);
assertEquals(msg1, new String(receiveBuffer.array(), 0, receiveBuffer.position()));
@@ -784,6 +789,10 @@
// Send a message. It should be filtered.
String msg2 = "Hello2";
sendMessage(sendingChannel, msg2, groupSocketAddress);
+ try {
+ IoBridge.poll(receivingChannel.socket().getFileDescriptor$(), POLLIN, 1000);
+ fail();
+ } catch (SocketTimeoutException expected) { }
receiveBuffer.position(0);
InetSocketAddress sourceAddress2 = (InetSocketAddress) receivingChannel.receive(receiveBuffer);
assertNull(sourceAddress2);
@@ -794,6 +803,7 @@
// Send a message. It should be received.
String msg3 = "Hello3";
sendMessage(sendingChannel, msg3, groupSocketAddress);
+ IoBridge.poll(receivingChannel.socket().getFileDescriptor$(), POLLIN, 1000);
receiveBuffer.position(0);
InetSocketAddress sourceAddress3 = (InetSocketAddress) receivingChannel.receive(receiveBuffer);
assertEquals(sourceAddress3, sendingAddress);
@@ -1236,6 +1246,5 @@
}
throw new AssertionFailedError("Unable to find local IPv6 address for " + networkInterface);
}
-
}
diff --git a/luni/src/test/java/libcore/java/util/FormatterTest.java b/luni/src/test/java/libcore/java/util/FormatterTest.java
index e87fee5..aed9ca0 100644
--- a/luni/src/test/java/libcore/java/util/FormatterTest.java
+++ b/luni/src/test/java/libcore/java/util/FormatterTest.java
@@ -17,7 +17,11 @@
package libcore.java.util;
import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
import java.util.Calendar;
+import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -183,4 +187,24 @@
assertEquals(expected, String.format(Locale.US, "%t" + pattern, c));
assertEquals(expected, String.format(Locale.US, "%T" + pattern, c));
}
+
+ // http://b/33245708: Some locales have a group separator != '\0' but a default decimal format
+ // pattern without grouping (e.g. a group size of zero). This would throw divide by zero when
+ // working out where to place the separator.
+ public void testGroupingSizeZero() {
+ Locale localeWithoutGrouping = new Locale("hy");
+ DecimalFormat decimalFormat =
+ (DecimalFormat) NumberFormat.getInstance(localeWithoutGrouping);
+
+ // Confirm the locale is still a good example: it has a group separator, but no grouping in
+ // the default decimal format.
+ assertEquals(0, decimalFormat.getGroupingSize());
+ assertFalse(decimalFormat.isGroupingUsed());
+ DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols();
+ assertTrue(symbols.getGroupingSeparator() != '\0');
+
+ Formatter formatter = new Formatter(localeWithoutGrouping);
+ formatter.format("%,d", 123456789);
+ // No exception expected
+ }
}
diff --git a/luni/src/test/java/libcore/io/Base64Test.java b/luni/src/test/java/libcore/java/util/LibcoreIoDerivedBase64Test.java
similarity index 78%
rename from luni/src/test/java/libcore/io/Base64Test.java
rename to luni/src/test/java/libcore/java/util/LibcoreIoDerivedBase64Test.java
index 6cfe186..2a888f7 100644
--- a/luni/src/test/java/libcore/io/Base64Test.java
+++ b/luni/src/test/java/libcore/java/util/LibcoreIoDerivedBase64Test.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package libcore.io;
+package libcore.java.util;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@@ -26,10 +26,16 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.Base64;
+import java.util.Base64.Decoder;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-public final class Base64Test extends TestCase {
+/**
+ * Additional tests for {@link java.util.Base64} derived from old tests for
+ * the removed class {@code libcore.io.Base64}.
+ */
+public final class LibcoreIoDerivedBase64Test extends TestCase {
public void testEncodeDecode() throws Exception {
assertEncodeDecode("");
@@ -59,7 +65,7 @@
for (int i = 0; i < toEncode.length; i++) {
inputBytes[i] = (byte) toEncode[i];
}
- String encoded = Base64.encode(inputBytes);
+ String encoded = encode(inputBytes);
assertEquals(expectedEncoded, encoded);
// Check we can round-trip the encoded bytes to
@@ -69,7 +75,7 @@
}
public void testDecode_empty() throws Exception {
- byte[] decoded = Base64.decode(new byte[0]);
+ byte[] decoded = decode(new byte[0]);
assertEquals(0, decoded.length);
}
@@ -78,26 +84,26 @@
assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxk"));
// The following are missing the final bytes
- assertEquals("hello, wo", decodeToString("aGVsbG8sIHdvcmx"));
- assertEquals("hello, wo", decodeToString("aGVsbG8sIHdvcm"));
- assertEquals("hello, wo", decodeToString("aGVsbG8sIHdvc"));
- assertEquals("hello, wo", decodeToString("aGVsbG8sIHdv"));
+ assertEquals("hello, worl", decodeToString("aGVsbG8sIHdvcmx"));
+ assertEquals("hello, wor", decodeToString("aGVsbG8sIHdvcm"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvc"));
+ assertEquals("hello, wo", decodeToString("aGVsbG8sIHdv"));
}
public void testDecode_extraChars() throws Exception {
// Characters outside of alphabet before padding.
- assertEquals("hello, world", decodeToString(" aGVsbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGV sbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxk "));
+ assertEquals(null, decodeToString(" aGVsbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGV sbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxk "));
assertEquals(null, decodeToString("*aGVsbG8sIHdvcmxk"));
assertEquals(null, decodeToString("aGV*sbG8sIHdvcmxk"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxk*"));
- assertEquals("hello, world", decodeToString("\r\naGVsbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGV\r\nsbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxk\r\n"));
- assertEquals("hello, world", decodeToString("\naGVsbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGV\nsbG8sIHdvcmxk"));
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxk\n"));
+ assertEquals(null, decodeToString("\r\naGVsbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGV\r\nsbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxk\r\n"));
+ assertEquals(null, decodeToString("\naGVsbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGV\nsbG8sIHdvcmxk"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxk\n"));
// padding 0
assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxk"));
@@ -111,49 +117,49 @@
// padding 1
assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE="));
// Missing padding
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxkPyE"));
+ assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE"));
// Characters outside alphabet before padding.
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE ="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE ="));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE*="));
// Trailing characters, otherwise valid.
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE= "));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE= "));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=*"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=X"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=XY"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=XYZ"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=XYZA"));
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE=\n"));
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE=\r\n"));
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE= "));
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE=="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=\n"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=\r\n"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE= "));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE=="));
// Whitespace characters outside alphabet intermixed with (too much) padding.
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE =="));
- assertEquals("hello, world?!", decodeToString("aGVsbG8sIHdvcmxkPyE = = "));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE =="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkPyE = = "));
// padding 2
assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg=="));
// Missing padding
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxkLg"));
+ assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg"));
// Partially missing padding
- assertEquals("hello, world", decodeToString("aGVsbG8sIHdvcmxkLg="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg="));
// Characters outside alphabet before padding.
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg =="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg =="));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg*=="));
// Trailing characters, otherwise valid.
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg== "));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg== "));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==*"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==X"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==XY"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==XYZ"));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==XYZA"));
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg==\n"));
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg==\r\n"));
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg== "));
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg==="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==\n"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==\r\n"));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg== "));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg==="));
// Characters outside alphabet inside padding.
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg= ="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg= ="));
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg=*="));
- assertEquals("hello, world.", decodeToString("aGVsbG8sIHdvcmxkLg=\r\n="));
+ assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg=\r\n="));
// Characters inside alphabet inside padding.
assertEquals(null, decodeToString("aGVsbG8sIHdvcmxkLg=X="));
@@ -206,7 +212,7 @@
*/
private static String decodeToString(String in) throws Exception {
byte[] bytes = asciiToBytes(in);
- byte[] out = Base64.decode(bytes);
+ byte[] out = decode(bytes);
if (out == null) {
return null;
}
@@ -251,10 +257,23 @@
/** Decodes an ASCII string, returning an int array. */
private static int[] decodeToInts(String in) throws Exception {
- byte[] bytes = Base64.decode(asciiToBytes(in));
+ byte[] bytes = decode(asciiToBytes(in));
return bytesToInts(bytes);
}
+ private static byte[] decode(byte[] encoded) {
+ Decoder decoder = Base64.getDecoder();
+ try {
+ return decoder.decode(encoded);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ private static String encode(byte[] data) {
+ return Base64.getEncoder().encodeToString(data);
+ }
+
/**
* Convert a byte[] to an int[]. int is used because it is more convenient to use ints in
* tests.
@@ -270,16 +289,6 @@
return ints;
}
- /** Assert that decoding 'in' throws ArrayIndexOutOfBoundsException. */
- private static void assertDecodeBad(String in) throws Exception {
- try {
- byte[] result = Base64.decode(asciiToBytes(in));
- fail("should have failed to decode. Actually received: " +
- (result == null ? result : Arrays.toString(bytesToInts(result))));
- } catch (ArrayIndexOutOfBoundsException e) {
- }
- }
-
private static void assertArrayEquals(int[] expected, int[] actual) {
assertSubArrayEquals(expected, expected.length, actual);
}
diff --git a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
index 4f5d658..5471b1f 100644
--- a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
+++ b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
@@ -120,6 +120,30 @@
expectExceptionInDNConstructor("l=\\g0");
}
+ public void testNegativeLen() {
+ try {
+ X500Principal p = new X500Principal(new byte[]{
+ 0x30, // DerValue.tag_Sequence read in DerValue#getSequence
+ 9, // Length of the vector. read in readVector.
+ // DerInputStream.getLength will just return this as 10 & 0x80 == 0
+ -1, // Tag of the first value in the sequencevalue. Convenient so that it
+ // doesn't hold DerIndefLenConverter.isEOC()
+ (byte) 0x80, // Encoding in indefinite form
+ -1, // Second tag to be read by DerIndefLenConverter
+ (byte) 0x84, // Second length byte to be read, 0x80 means long form, 4 bytes
+ (byte) 0xff, // Length to be read by DerIndefLenConverter, -6, will move the
+ // buffer position to the second tag
+ (byte) 0xff,
+ (byte) 0xff,
+ (byte) -6,
+ 0, // Needed as otherwise it's detected that there's nothing after
+ // the length
+ });
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
private void expectExceptionInDNConstructor(String dn) {
try {
X500Principal principal = new X500Principal(dn);
diff --git a/luni/src/test/java/libcore/sun/security/x509/AlgorithmIdTest.java b/luni/src/test/java/libcore/sun/security/x509/AlgorithmIdTest.java
index c2ab862..b20816f 100644
--- a/luni/src/test/java/libcore/sun/security/x509/AlgorithmIdTest.java
+++ b/luni/src/test/java/libcore/sun/security/x509/AlgorithmIdTest.java
@@ -48,6 +48,13 @@
"2.16.840.1.101.3.4.3.1", AlgorithmId.get("sHA224withDSA").getOID().toString());
assertEquals(
"2.16.840.1.101.3.4.3.2", AlgorithmId.get("sHA256withDSA").getOID().toString());
+
+ // Used to be 2.16.840.1.101.3.4.42 until N because BouncyCastle accepts this alias. It
+ // started with a typo they once had and for compatibility they still support it. Since we
+ // scan the aliases, we were picking it as the canonical OID for AES. See:
+ // http://www.docjar.org/html/api/org/bouncycastle/jce/provider/symmetric/AESMappings.java.html
+ assertEquals("2.16.840.1.101.3.4.1", AlgorithmId.get("AES").getOID().toString());
+ assertEquals("1.3.132.1.12", AlgorithmId.get("ECDH").getOID().toString());
}
public void test_getName() throws Exception {
@@ -61,6 +68,15 @@
assertEquals("SHA256withDSA", getOidName("2.16.840.1.101.3.4.3.2"));
assertEquals("SHA224withRSA", getOidName("1.2.840.113549.1.1.14"));
+ assertEquals("AES", getOidName("2.16.840.1.101.3.4.1"));
+ // AES is also the result of 2.16.840.1.101.3.4.42 because BouncyCastle accepts this alias.
+ // It started with a typo they once had and for compatibility they still support it. Since
+ // we scan the aliases, we were picking it. See:
+ // http://www.docjar.org/html/api/org/bouncycastle/jce/provider/symmetric/AESMappings.java.html
+ assertEquals("AES", getOidName("2.16.840.1.101.3.4.42"));
+
+ // ECDH not present before and in N
+ assertEquals("ECDH", getOidName("1.3.132.1.12"));
}
private String getOidName(String oid) throws Exception {
diff --git a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
index 12ad0d7..7fa46d5 100644
--- a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
@@ -29,36 +29,38 @@
System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo/tzdata";
// An empty override file should fall back to the default file.
- public void testEmptyOverrideFile() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ public void testLoadTzDataWithFallback_emptyOverrideFile() throws Exception {
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String emptyFilePath = makeEmptyFile().getPath();
+
ZoneInfoDB.TzData dataWithEmptyOverride =
- new ZoneInfoDB.TzData(emptyFilePath, TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath, TZDATA_IN_ROOT);
assertEquals(data.getVersion(), dataWithEmptyOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithEmptyOverride.getAvailableIDs().length);
}
// A corrupt override file should fall back to the default file.
- public void testCorruptOverrideFile() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ public void testLoadTzDataWithFallback_corruptOverrideFile() throws Exception {
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String corruptFilePath = makeCorruptFile().getPath();
+
ZoneInfoDB.TzData dataWithCorruptOverride =
- new ZoneInfoDB.TzData(corruptFilePath, TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(corruptFilePath, TZDATA_IN_ROOT);
assertEquals(data.getVersion(), dataWithCorruptOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithCorruptOverride.getAvailableIDs().length);
}
// Given no tzdata files we can use, we should fall back to built-in "GMT".
- public void testNoGoodFile() throws Exception {
+ public void testLoadTzDataWithFallback_noGoodFile() throws Exception {
String emptyFilePath = makeEmptyFile().getPath();
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(emptyFilePath);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath);
assertEquals("missing", data.getVersion());
assertEquals(1, data.getAvailableIDs().length);
assertEquals("GMT", data.getAvailableIDs()[0]);
}
// Given a valid override file, we should find ourselves using that.
- public void testGoodOverrideFile() throws Exception {
+ public void testLoadTzDataWithFallback_goodOverrideFile() throws Exception {
RandomAccessFile in = new RandomAccessFile(TZDATA_IN_ROOT, "r");
byte[] content = new byte[(int) in.length()];
in.readFully(content);
@@ -70,11 +72,11 @@
content[10] = 'z';
in.close();
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
File goodFile = makeTemporaryFile(content);
try {
ZoneInfoDB.TzData dataWithOverride =
- new ZoneInfoDB.TzData(goodFile.getPath(), TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData.loadTzDataWithFallback(goodFile.getPath(), TZDATA_IN_ROOT);
assertEquals("9999z", dataWithOverride.getVersion());
assertEquals(data.getAvailableIDs().length, dataWithOverride.getAvailableIDs().length);
} finally {
@@ -84,7 +86,7 @@
// Confirms any caching that exists correctly handles TimeZone mutability.
public void testMakeTimeZone_timeZoneMutability() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String tzId = "Europe/London";
ZoneInfo first = data.makeTimeZone(tzId);
ZoneInfo second = data.makeTimeZone(tzId);
@@ -101,19 +103,19 @@
}
public void testMakeTimeZone_notFound() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
assertNull(data.makeTimeZone("THIS_TZ_DOES_NOT_EXIST"));
assertFalse(data.hasTimeZone("THIS_TZ_DOES_NOT_EXIST"));
}
public void testMakeTimeZone_found() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
assertNotNull(data.makeTimeZone("Europe/London"));
assertTrue(data.hasTimeZone("Europe/London"));
}
public void testGetRulesVersion() throws Exception {
- ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_IN_ROOT);
String rulesVersion = ZoneInfoDB.TzData.getRulesVersion(new File(TZDATA_IN_ROOT));
assertEquals(data.getVersion(), rulesVersion);
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index c1a7565..3d11475 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -374,7 +374,6 @@
luni/src/main/java/libcore/internal/StringPool.java \
luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java \
luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java \
- luni/src/main/java/libcore/io/Base64.java \
luni/src/main/java/libcore/io/BlockGuardOs.java \
luni/src/main/java/libcore/io/BufferIterator.java \
luni/src/main/java/libcore/io/DropBox.java \
diff --git a/ojluni/src/main/java/java/net/HttpCookie.java b/ojluni/src/main/java/java/net/HttpCookie.java
index 8aae078..3cdd438 100644
--- a/ojluni/src/main/java/java/net/HttpCookie.java
+++ b/ojluni/src/main/java/java/net/HttpCookie.java
@@ -1013,8 +1013,8 @@
long maxAgeInSeconds = 0;
if (date != null) {
maxAgeInSeconds = (date.getTime() - cookie.whenCreated) / 1000;
- // If "expires" is in the past, remove the cookie.
- if (maxAgeInSeconds < 0) {
+ // Avoid MAX_AGE_UNSPECIFIED
+ if (maxAgeInSeconds == MAX_AGE_UNSPECIFIED) {
maxAgeInSeconds = 0;
}
}
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
index c94bc37..9dbb8a6 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
@@ -37,7 +37,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
index f9c13fa..ff4a6bf 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
@@ -38,7 +38,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
index 667c8bd..8e4e2e8 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
@@ -37,7 +37,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
index 275f37e..e340426 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
@@ -37,7 +37,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
index 1ea65e3..70f59c9 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
@@ -37,7 +37,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
index 90aec35..5178a7e 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
@@ -37,7 +37,7 @@
int mark, int pos, int lim, int cap,
int off, ByteOrder order) {
super(mark, pos, lim, cap);
- this.bb = bb;
+ this.bb = bb.duplicate();
this.isReadOnly = bb.isReadOnly;
// There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
// HeapByteBuffer. We only have to initialize the field when bb is an instance of
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index ebfdd2d..d6d8502 100644
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -4191,6 +4191,14 @@
grpSep = dfs.getGroupingSeparator();
DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
grpSize = df.getGroupingSize();
+ // Android-changed: http://b/33245708 : Some locales have a group separator but
+ // also patterns without groups. If we do not clear the group separator in these
+ // cases a divide by zero is thrown when determining where to place the
+ // separators.
+ if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
+ grpSep = '\0';
+ }
+ // Android-changed: end http://b/33245708.
}
}
diff --git a/ojluni/src/main/java/java/util/zip/ZipFile.java b/ojluni/src/main/java/java/util/zip/ZipFile.java
old mode 100755
new mode 100644
diff --git a/ojluni/src/main/java/sun/security/pkcs/PKCS9Attribute.java b/ojluni/src/main/java/sun/security/pkcs/PKCS9Attribute.java
index 9ae4a99..d847b10 100644
--- a/ojluni/src/main/java/sun/security/pkcs/PKCS9Attribute.java
+++ b/ojluni/src/main/java/sun/security/pkcs/PKCS9Attribute.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -331,11 +331,11 @@
{new Byte(DerValue.tag_Sequence)} // SignatureTimestampToken
};
- private static final Class[] VALUE_CLASSES = new Class[18];
+ private static final Class<?>[] VALUE_CLASSES = new Class<?>[18];
static {
try {
- Class str = Class.forName("[Ljava.lang.String;");
+ Class<?> str = Class.forName("[Ljava.lang.String;");
VALUE_CLASSES[0] = null; // not used
VALUE_CLASSES[1] = str; // EMailAddress
@@ -489,8 +489,8 @@
if (val.length != 2)
throw new IOException("PKCS9Attribute doesn't have two components");
- // get the oid
+ // get the oid
oid = val[0].getOID();
byte[] content = val[1].toByteArray();
DerValue[] elems = new DerInputStream(content).getSet(1);
diff --git a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
index 3a024b0..e5f3e1d 100644
--- a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
+++ b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
@@ -327,7 +327,7 @@
authenticatedAttributes.getAttributeValue(
PKCS9Attribute.CONTENT_TYPE_OID);
if (contentType == null ||
- !contentType.equals(content.contentType))
+ !contentType.equals((Object)content.contentType))
return null; // contentType does not match, bad SignerInfo
// now, check message digest
diff --git a/ojluni/src/main/java/sun/security/provider/X509Factory.java b/ojluni/src/main/java/sun/security/provider/X509Factory.java
index 0c047a6..19e70c0 100644
--- a/ojluni/src/main/java/sun/security/provider/X509Factory.java
+++ b/ojluni/src/main/java/sun/security/provider/X509Factory.java
@@ -25,18 +25,24 @@
package sun.security.provider;
+/* BEGIN android-removed
import java.io.*;
import java.util.*;
+ * END android-removed */
import java.security.cert.*;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CRLImpl;
+/* BEGIN android-removed
import sun.security.pkcs.PKCS7;
import sun.security.provider.certpath.X509CertPath;
import sun.security.provider.certpath.X509CertificatePair;
import sun.security.util.DerValue;
+ * END android-removed */
import sun.security.util.Cache;
-import sun.misc.BASE64Decoder;
+/* BEGIN android-removed
+import java.util.Base64;
import sun.security.pkcs.ParsingException;
+ * END android-removed */
/**
* This class defines a certificate factory for X.509 v3 certificates &
@@ -57,10 +63,15 @@
* @see sun.security.x509.X509CRLImpl
*/
-public class X509Factory extends CertificateFactorySpi {
+// BEGIN android-changed
+// Was: public class X509Factory extends CertificateFactorySpi {
+public class X509Factory {
+// END android-changed
+ /* BEGIN android-removed
public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
public static final String END_CERT = "-----END CERTIFICATE-----";
+ * END android-removed */
private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX
@@ -69,6 +80,7 @@
private static final Cache<Object, X509CRLImpl> crlCache
= Cache.newSoftMemoryCache(750);
+ /* BEGIN android-removed
/**
* Generates an X.509 certificate object and initializes it with
* the data read from the input stream <code>is</code>.
@@ -79,7 +91,7 @@
* from the input stream.
*
* @exception CertificateException on parsing errors.
- */
+ *
@Override
public Certificate engineGenerateCertificate(InputStream is)
throws CertificateException
@@ -112,7 +124,7 @@
/**
* Read from the stream until length bytes have been read or EOF has
* been reached. Return the number of bytes actually read.
- */
+ *
private static int readFully(InputStream in, ByteArrayOutputStream bout,
int length) throws IOException {
int read = 0;
@@ -128,6 +140,7 @@
}
return read;
}
+ * END android-removed */
/**
* Return an interned X509CertImpl for the given certificate.
@@ -231,6 +244,7 @@
cache.put(key, value);
}
+ /* BEGIN android-removed
/**
* Generates a <code>CertPath</code> object and initializes it with
* the data read from the <code>InputStream</code> inStream. The data
@@ -241,7 +255,7 @@
* <code>InputStream</code>
* @exception CertificateException if an exception occurs while decoding
* @since 1.4
- */
+ *
@Override
public CertPath engineGenerateCertPath(InputStream inStream)
throws CertificateException
@@ -273,7 +287,7 @@
* @exception CertificateException if an exception occurs while decoding or
* the encoding requested is not supported
* @since 1.4
- */
+ *
@Override
public CertPath engineGenerateCertPath(InputStream inStream,
String encoding) throws CertificateException
@@ -306,7 +320,7 @@
* certificates
* @exception CertificateException if an exception occurs
* @since 1.4
- */
+ *
@Override
public CertPath
engineGenerateCertPath(List<? extends Certificate> certificates)
@@ -326,7 +340,7 @@
* @return an <code>Iterator</code> over the names of the supported
* <code>CertPath</code> encodings (as <code>String</code>s)
* @since 1.4
- */
+ *
@Override
public Iterator<String> engineGetCertPathEncodings() {
return(X509CertPath.getEncodingsStatic());
@@ -342,7 +356,7 @@
* initialized with the data from the input stream.
*
* @exception CertificateException on parsing errors.
- */
+ *
@Override
public Collection<? extends java.security.cert.Certificate>
engineGenerateCertificates(InputStream is)
@@ -368,7 +382,7 @@
* from the input stream.
*
* @exception CRLException on parsing errors.
- */
+ *
@Override
public CRL engineGenerateCRL(InputStream is)
throws CRLException
@@ -406,7 +420,7 @@
* initialized with the data from the input stream.
*
* @exception CRLException on parsing errors.
- */
+ *
@Override
public Collection<? extends java.security.cert.CRL> engineGenerateCRLs(
InputStream is) throws CRLException
@@ -425,16 +439,35 @@
* Parses the data in the given input stream as a sequence of DER
* encoded X.509 certificates (in binary or base 64 encoded format) OR
* as a single PKCS#7 encoded blob (in binary or base64 encoded format).
- */
+ *
private Collection<? extends java.security.cert.Certificate>
parseX509orPKCS7Cert(InputStream is)
throws CertificateException, IOException
{
+ int peekByte;
+ byte[] data;
+ PushbackInputStream pbis = new PushbackInputStream(is);
Collection<X509CertImpl> coll = new ArrayList<>();
- byte[] data = readOneBlock(is);
- if (data == null) {
+
+ // Test the InputStream for end-of-stream. If the stream's
+ // initial state is already at end-of-stream then return
+ // an empty collection. Otherwise, push the byte back into the
+ // stream and let readOneBlock look for the first certificate.
+ peekByte = pbis.read();
+ if (peekByte == -1) {
return new ArrayList<>(0);
+ } else {
+ pbis.unread(peekByte);
+ data = readOneBlock(pbis);
}
+
+ // If we end up with a null value after reading the first block
+ // then we know the end-of-stream has been reached and no certificate
+ // data has been found.
+ if (data == null) {
+ throw new CertificateException("No certificate data found");
+ }
+
try {
PKCS7 pkcs7 = new PKCS7(data);
X509Certificate[] certs = pkcs7.getCertificates();
@@ -442,13 +475,13 @@
if (certs != null) {
return Arrays.asList(certs);
} else {
- // no crls provided
+ // no certificates provided
return new ArrayList<>(0);
}
} catch (ParsingException e) {
while (data != null) {
coll.add(new X509CertImpl(data));
- data = readOneBlock(is);
+ data = readOneBlock(pbis);
}
}
return coll;
@@ -458,16 +491,35 @@
* Parses the data in the given input stream as a sequence of DER encoded
* X.509 CRLs (in binary or base 64 encoded format) OR as a single PKCS#7
* encoded blob (in binary or base 64 encoded format).
- */
+ *
private Collection<? extends java.security.cert.CRL>
parseX509orPKCS7CRL(InputStream is)
throws CRLException, IOException
{
+ int peekByte;
+ byte[] data;
+ PushbackInputStream pbis = new PushbackInputStream(is);
Collection<X509CRLImpl> coll = new ArrayList<>();
- byte[] data = readOneBlock(is);
- if (data == null) {
+
+ // Test the InputStream for end-of-stream. If the stream's
+ // initial state is already at end-of-stream then return
+ // an empty collection. Otherwise, push the byte back into the
+ // stream and let readOneBlock look for the first CRL.
+ peekByte = pbis.read();
+ if (peekByte == -1) {
return new ArrayList<>(0);
+ } else {
+ pbis.unread(peekByte);
+ data = readOneBlock(pbis);
}
+
+ // If we end up with a null value after reading the first block
+ // then we know the end-of-stream has been reached and no CRL
+ // data has been found.
+ if (data == null) {
+ throw new CRLException("No CRL data found");
+ }
+
try {
PKCS7 pkcs7 = new PKCS7(data);
X509CRL[] crls = pkcs7.getCRLs();
@@ -481,7 +533,7 @@
} catch (ParsingException e) {
while (data != null) {
coll.add(new X509CRLImpl(data));
- data = readOneBlock(is);
+ data = readOneBlock(pbis);
}
}
return coll;
@@ -498,7 +550,7 @@
* @param is the InputStream
* @returns byte block or null if end of stream
* @throws IOException If any parsing error
- */
+ *
private static byte[] readOneBlock(InputStream is) throws IOException {
// The first character of a BLOCK.
@@ -595,8 +647,7 @@
checkHeaderFooter(header.toString(), footer.toString());
- BASE64Decoder decoder = new BASE64Decoder();
- return decoder.decodeBuffer(new String(data, 0, pos));
+ return Base64.getMimeDecoder().decode(new String(data, 0, pos));
}
}
@@ -627,7 +678,7 @@
* @param tag Tag already read (-1 mean not read)
* @returns The current tag, used to check EOC in indefinite-length BER
* @throws IOException Any parsing error
- */
+ *
private static int readBERInternal(InputStream is,
ByteArrayOutputStream bout, int tag) throws IOException {
@@ -716,4 +767,5 @@
}
return tag;
}
+ * END android-removed */
}
diff --git a/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java b/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
index 78d9e30..cbd5ecc 100644
--- a/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
+++ b/ojluni/src/main/java/sun/security/util/DerIndefLenConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -156,12 +156,18 @@
}
if (isLongForm(lenByte)) {
lenByte &= LEN_MASK;
- if (lenByte > 4)
+ if (lenByte > 4) {
throw new IOException("Too much data");
- if ((dataSize - dataPos) < (lenByte + 1))
+ }
+ if ((dataSize - dataPos) < (lenByte + 1)) {
throw new IOException("Too little data");
- for (int i = 0; i < lenByte; i++)
+ }
+ for (int i = 0; i < lenByte; i++) {
curLen = (curLen << 8) + (data[dataPos++] & 0xff);
+ }
+ if (curLen < 0) {
+ throw new IOException("Invalid length bytes");
+ }
} else {
curLen = (lenByte & LEN_MASK);
}
@@ -188,10 +194,15 @@
}
if (isLongForm(lenByte)) {
lenByte &= LEN_MASK;
- for (int i = 0; i < lenByte; i++)
+ for (int i = 0; i < lenByte; i++) {
curLen = (curLen << 8) + (data[dataPos++] & 0xff);
- } else
+ }
+ if (curLen < 0) {
+ throw new IOException("Invalid length bytes");
+ }
+ } else {
curLen = (lenByte & LEN_MASK);
+ }
writeLength(curLen);
writeValue(curLen);
}
diff --git a/ojluni/src/main/java/sun/security/util/DerInputStream.java b/ojluni/src/main/java/sun/security/util/DerInputStream.java
index 8f51439..dae8afd 100644
--- a/ojluni/src/main/java/sun/security/util/DerInputStream.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputStream.java
@@ -604,6 +604,10 @@
value <<= 8;
value += 0x0ff & in.read();
}
+ if (value < 0) {
+ throw new IOException("DerInputStream.getLength(): "
+ + "Invalid length bytes");
+ }
}
return value;
}
diff --git a/ojluni/src/main/java/sun/security/x509/AVA.java b/ojluni/src/main/java/sun/security/x509/AVA.java
index f28ab9b..8a85d7b 100644
--- a/ojluni/src/main/java/sun/security/x509/AVA.java
+++ b/ojluni/src/main/java/sun/security/x509/AVA.java
@@ -379,8 +379,8 @@
// encode as PrintableString unless value contains
// non-PrintableString chars
- if (this.oid.equals(PKCS9Attribute.EMAIL_ADDRESS_OID) ||
- (this.oid.equals(X500Name.DOMAIN_COMPONENT_OID) &&
+ if (this.oid.equals((Object)PKCS9Attribute.EMAIL_ADDRESS_OID) ||
+ (this.oid.equals((Object)X500Name.DOMAIN_COMPONENT_OID) &&
PRESERVE_OLD_DC_ENCODING == false)) {
// EmailAddress and DomainComponent must be IA5String
return new DerValue(DerValue.tag_IA5String,
@@ -396,7 +396,7 @@
private DerValue parseString
(Reader in, int c, int format, StringBuilder temp) throws IOException {
- List<Byte> embeddedHex = new ArrayList<Byte>();
+ List<Byte> embeddedHex = new ArrayList<>();
boolean isPrintableString = true;
boolean escape = false;
boolean leadingChar = true;
@@ -514,8 +514,8 @@
// encode as PrintableString unless value contains
// non-PrintableString chars
- if (this.oid.equals(PKCS9Attribute.EMAIL_ADDRESS_OID) ||
- (this.oid.equals(X500Name.DOMAIN_COMPONENT_OID) &&
+ if (this.oid.equals((Object)PKCS9Attribute.EMAIL_ADDRESS_OID) ||
+ (this.oid.equals((Object)X500Name.DOMAIN_COMPONENT_OID) &&
PRESERVE_OLD_DC_ENCODING == false)) {
// EmailAddress and DomainComponent must be IA5String
return new DerValue(DerValue.tag_IA5String, temp.toString());
diff --git a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
index 903a12d..1bdb1b8 100644
--- a/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
+++ b/ojluni/src/main/java/sun/security/x509/AlgorithmId.java
@@ -235,7 +235,7 @@
if (algName != null) {
return algName;
}
- if ((params != null) && algid.equals(specifiedWithECDSA_oid)) {
+ if ((params != null) && algid.equals((Object)specifiedWithECDSA_oid)) {
try {
AlgorithmId paramsId =
AlgorithmId.parse(new DerValue(getEncodedParams()));
@@ -276,7 +276,7 @@
public boolean equals(AlgorithmId other) {
boolean paramsEqual =
(params == null ? other.params == null : params.equals(other.params));
- return (algid.equals(other.algid) && paramsEqual);
+ return (algid.equals((Object)other.algid) && paramsEqual);
}
/**
@@ -304,7 +304,7 @@
* they are the same algorithm, ignoring algorithm parameters.
*/
public final boolean equals(ObjectIdentifier id) {
- return algid.equals(id);
+ return algid.equals((Object)id);
}
/**
@@ -510,6 +510,14 @@
if (name.equalsIgnoreCase("EC")) {
return EC_oid;
}
+ if (name.equalsIgnoreCase("ECDH")) {
+ return AlgorithmId.ECDH_oid;
+ }
+
+ // Secret key algorithms
+ if (name.equalsIgnoreCase("AES")) {
+ return AlgorithmId.AES_oid;
+ }
// Common signature types
if (name.equalsIgnoreCase("MD5withRSA")
@@ -705,10 +713,17 @@
public static final ObjectIdentifier DSA_oid;
public static final ObjectIdentifier DSA_OIW_oid;
public static final ObjectIdentifier EC_oid = oid(1, 2, 840, 10045, 2, 1);
+ public static final ObjectIdentifier ECDH_oid = oid(1, 3, 132, 1, 12);
public static final ObjectIdentifier RSA_oid;
public static final ObjectIdentifier RSAEncryption_oid;
/*
+ * COMMON SECRET KEY TYPES
+ */
+ public static final ObjectIdentifier AES_oid =
+ oid(2, 16, 840, 1, 101, 3, 4, 1);
+
+ /*
* COMMON SIGNATURE ALGORITHMS
*/
private static final int md2WithRSAEncryption_data[] =
@@ -938,6 +953,10 @@
nameTable.put(DSA_oid, "DSA");
nameTable.put(DSA_OIW_oid, "DSA");
nameTable.put(EC_oid, "EC");
+ nameTable.put(ECDH_oid, "ECDH");
+
+ nameTable.put(AES_oid, "AES");
+
nameTable.put(sha1WithECDSA_oid, "SHA1withECDSA");
nameTable.put(sha224WithECDSA_oid, "SHA224withECDSA");
nameTable.put(sha256WithECDSA_oid, "SHA256withECDSA");
diff --git a/ojluni/src/main/java/sun/security/x509/DistributionPointName.java b/ojluni/src/main/java/sun/security/x509/DistributionPointName.java
index 19d6289..4409dc0 100644
--- a/ojluni/src/main/java/sun/security/x509/DistributionPointName.java
+++ b/ojluni/src/main/java/sun/security/x509/DistributionPointName.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
diff --git a/ojluni/src/main/java/sun/security/x509/NetscapeCertTypeExtension.java b/ojluni/src/main/java/sun/security/x509/NetscapeCertTypeExtension.java
index 78f731b..735efdd 100644
--- a/ojluni/src/main/java/sun/security/x509/NetscapeCertTypeExtension.java
+++ b/ojluni/src/main/java/sun/security/x509/NetscapeCertTypeExtension.java
@@ -221,7 +221,7 @@
/**
* Get the attribute value.
*/
- public Object get(String name) throws IOException {
+ public Boolean get(String name) throws IOException {
return Boolean.valueOf(isSet(getPosition(name)));
}
@@ -314,15 +314,15 @@
if (isSet(getPosition(SSL_CLIENT)) ||
isSet(getPosition(S_MIME)) ||
isSet(getPosition(OBJECT_SIGNING)))
- keyUsage.set(keyUsage.DIGITAL_SIGNATURE, val);
+ keyUsage.set(KeyUsageExtension.DIGITAL_SIGNATURE, val);
if (isSet(getPosition(SSL_SERVER)))
- keyUsage.set(keyUsage.KEY_ENCIPHERMENT, val);
+ keyUsage.set(KeyUsageExtension.KEY_ENCIPHERMENT, val);
if (isSet(getPosition(SSL_CA)) ||
isSet(getPosition(S_MIME_CA)) ||
isSet(getPosition(OBJECT_SIGNING_CA)))
- keyUsage.set(keyUsage.KEY_CERTSIGN, val);
+ keyUsage.set(KeyUsageExtension.KEY_CERTSIGN, val);
} catch (IOException e) { }
return keyUsage.getBits();
}
diff --git a/ojluni/src/main/java/sun/security/x509/RDN.java b/ojluni/src/main/java/sun/security/x509/RDN.java
index 1463fd1..ed46abe 100644
--- a/ojluni/src/main/java/sun/security/x509/RDN.java
+++ b/ojluni/src/main/java/sun/security/x509/RDN.java
@@ -26,17 +26,11 @@
package sun.security.x509;
-import java.lang.reflect.*;
import java.io.IOException;
import java.io.StringReader;
-import java.security.PrivilegedExceptionAction;
-import java.security.AccessController;
-import java.security.Principal;
import java.util.*;
import sun.security.util.*;
-import sun.security.pkcs.PKCS9Attribute;
-import javax.security.auth.x500.X500Principal;
/**
* RDNs are a set of {attribute = value} assertions. Some of those
@@ -328,7 +322,7 @@
*/
DerValue findAttribute(ObjectIdentifier oid) {
for (int i = 0; i < assertion.length; i++) {
- if (assertion[i].oid.equals(oid)) {
+ if (assertion[i].oid.equals((Object)oid)) {
return assertion[i].value;
}
}
diff --git a/ojluni/src/main/java/sun/security/x509/X500Name.java b/ojluni/src/main/java/sun/security/x509/X500Name.java
index 7b24fa3..6090554 100644
--- a/ojluni/src/main/java/sun/security/x509/X500Name.java
+++ b/ojluni/src/main/java/sun/security/x509/X500Name.java
@@ -28,14 +28,12 @@
import java.lang.reflect.*;
import java.io.IOException;
-import java.io.StringReader;
import java.security.PrivilegedExceptionAction;
import java.security.AccessController;
import java.security.Principal;
import java.util.*;
import sun.security.util.*;
-import sun.security.pkcs.PKCS9Attribute;
import javax.security.auth.x500.X500Principal;
/**
@@ -1392,7 +1390,7 @@
/**
* Constructor object for use by asX500Principal().
*/
- private static final Constructor principalConstructor;
+ private static final Constructor<X500Principal> principalConstructor;
/**
* Field object for use by asX500Name().
@@ -1407,9 +1405,9 @@
PrivilegedExceptionAction<Object[]> pa =
new PrivilegedExceptionAction<Object[]>() {
public Object[] run() throws Exception {
- Class pClass = X500Principal.class;
- Class[] args = new Class[] {X500Name.class};
- Constructor cons = ((Class<?>)pClass).getDeclaredConstructor(args);
+ Class<X500Principal> pClass = X500Principal.class;
+ Class<?>[] args = new Class<?>[] { X500Name.class };
+ Constructor<X500Principal> cons = pClass.getDeclaredConstructor(args);
cons.setAccessible(true);
Field field = pClass.getDeclaredField("thisX500Name");
field.setAccessible(true);
@@ -1418,7 +1416,10 @@
};
try {
Object[] result = AccessController.doPrivileged(pa);
- principalConstructor = (Constructor)result[0];
+ @SuppressWarnings("unchecked")
+ Constructor<X500Principal> constr =
+ (Constructor<X500Principal>)result[0];
+ principalConstructor = constr;
principalField = (Field)result[1];
} catch (Exception e) {
throw new InternalError("Could not obtain X500Principal access", e);
@@ -1435,8 +1436,7 @@
if (x500Principal == null) {
try {
Object[] args = new Object[] {this};
- x500Principal =
- (X500Principal)principalConstructor.newInstance(args);
+ x500Principal = principalConstructor.newInstance(args);
} catch (Exception e) {
throw new RuntimeException("Unexpected exception", e);
}
diff --git a/ojluni/src/main/native/PlainDatagramSocketImpl.c b/ojluni/src/main/native/PlainDatagramSocketImpl.c
index aad8c34..b36e286 100644
--- a/ojluni/src/main/native/PlainDatagramSocketImpl.c
+++ b/ojluni/src/main/native/PlainDatagramSocketImpl.c
@@ -500,6 +500,7 @@
}
if (IS_NULL(addressObj)) {
JNU_ThrowNullPointerException(env, "Null address in peek()");
+ return -1;
}
if (timeout) {
int ret = NET_Timeout(fd, timeout);
@@ -1386,7 +1387,7 @@
default :
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"Socket option not supported by PlainDatagramSocketImp");
- break;
+ return;
}
@@ -1608,6 +1609,9 @@
#ifdef AF_INET6
#ifdef __linux__
setTTL(env, fd, ttl);
+ if ((*env)->ExceptionCheck(env)) {
+ return;
+ }
if (ipv6_available()) {
setHopLimit(env, fd, ttl);
}
@@ -1830,6 +1834,7 @@
else
NET_ThrowCurrent(env, "setsockopt IP_DROP_MEMBERSHIP failed");
}
+ return;
}
}
diff --git a/ojluni/src/main/native/net_util_md.c b/ojluni/src/main/native/net_util_md.c
index 0dd6c09..49c9779 100644
--- a/ojluni/src/main/native/net_util_md.c
+++ b/ojluni/src/main/native/net_util_md.c
@@ -500,7 +500,9 @@
}
}
-#if defined(__linux__) && defined(AF_INET6)
+#if 0
+// Android-changed: Stripped out unused code. http://b/33250070
+// #if defined(__linux__) && defined(AF_INET6)
/* following code creates a list of addresses from the kernel
@@ -1398,9 +1400,12 @@
return timeout;
}
+#if 0
+// Stripped out unused code.
// http://b/27301951
__attribute__((destructor))
static void netUtilCleanUp() {
if (loRoutes != 0) free(loRoutes);
if (localifs != 0) free(localifs);
}
+#endif
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TzDataBundleInstaller.java b/tzdata/update2/src/main/libcore/tzdata/update2/TzDataBundleInstaller.java
index b8e8bdf..127baf8 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TzDataBundleInstaller.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TzDataBundleInstaller.java
@@ -29,18 +29,37 @@
*/
public final class TzDataBundleInstaller {
- static final String CURRENT_TZ_DATA_DIR_NAME = "current";
- static final String WORKING_DIR_NAME = "working";
- static final String OLD_TZ_DATA_DIR_NAME = "old";
+ private static final String CURRENT_TZ_DATA_DIR_NAME = "current";
+ private static final String WORKING_DIR_NAME = "working";
+ private static final String OLD_TZ_DATA_DIR_NAME = "old";
private final String logTag;
private final File systemTzDataFile;
- private final File installDir;
+ private final File oldTzDataDir;
+ private final File currentTzDataDir;
+ private final File workingDir;
public TzDataBundleInstaller(String logTag, File systemTzDataFile, File installDir) {
this.logTag = logTag;
this.systemTzDataFile = systemTzDataFile;
- this.installDir = installDir;
+ oldTzDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME);
+ currentTzDataDir = new File(installDir, CURRENT_TZ_DATA_DIR_NAME);
+ workingDir = new File(installDir, WORKING_DIR_NAME);
+ }
+
+ // VisibleForTesting
+ File getOldTzDataDir() {
+ return oldTzDataDir;
+ }
+
+ // VisibleForTesting
+ File getCurrentTzDataDir() {
+ return currentTzDataDir;
+ }
+
+ // VisibleForTesting
+ File getWorkingDir() {
+ return workingDir;
}
/**
@@ -51,29 +70,28 @@
* If the installation completed successfully this method returns {@code true}.
*/
public boolean install(byte[] content) throws IOException {
- File oldTzDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME);
if (oldTzDataDir.exists()) {
FileUtils.deleteRecursive(oldTzDataDir);
}
-
- File currentTzDataDir = new File(installDir, CURRENT_TZ_DATA_DIR_NAME);
- File workingDir = new File(installDir, WORKING_DIR_NAME);
+ if (workingDir.exists()) {
+ FileUtils.deleteRecursive(workingDir);
+ }
Slog.i(logTag, "Unpacking / verifying time zone update");
- File unpackedContentDir = unpackBundle(content, workingDir);
+ unpackBundle(content, workingDir);
try {
- if (!checkBundleVersion(unpackedContentDir)) {
+ if (!checkBundleVersion(workingDir)) {
Slog.i(logTag, "Update not applied: Bundle format version is incorrect.");
return false;
}
// This check should not fail if the bundle version check passes, but we're being
// intentionally paranoid.
- if (!checkBundleFilesExist(unpackedContentDir)) {
+ if (!checkBundleFilesExist(workingDir)) {
Slog.i(logTag, "Update not applied: Bundle is missing files");
return false;
}
- if (!checkBundleRulesNewerThanSystem(systemTzDataFile, unpackedContentDir)) {
+ if (!checkBundleRulesNewerThanSystem(systemTzDataFile, workingDir)) {
Slog.i(logTag, "Update not applied: Bundle rules version check failed");
return false;
}
@@ -82,19 +100,52 @@
// http://b/31008728
Slog.i(logTag, "Applying time zone update");
- FileUtils.makeDirectoryWorldAccessible(unpackedContentDir);
+ FileUtils.makeDirectoryWorldAccessible(workingDir);
if (currentTzDataDir.exists()) {
Slog.i(logTag, "Moving " + currentTzDataDir + " to " + oldTzDataDir);
FileUtils.rename(currentTzDataDir, oldTzDataDir);
}
- Slog.i(logTag, "Moving " + unpackedContentDir + " to " + currentTzDataDir);
- FileUtils.rename(unpackedContentDir, currentTzDataDir);
+ Slog.i(logTag, "Moving " + workingDir + " to " + currentTzDataDir);
+ FileUtils.rename(workingDir, currentTzDataDir);
Slog.i(logTag, "Update applied: " + currentTzDataDir + " successfully created");
return true;
} finally {
deleteBestEffort(oldTzDataDir);
- deleteBestEffort(unpackedContentDir);
+ deleteBestEffort(workingDir);
+ }
+ }
+
+ /**
+ * Uninstall the current timezone update in /data, returning the device to using data from
+ * /system. Returns {@code true} if uninstallation was successful, {@code false} if there was
+ * nothing installed in /data to uninstall.
+ *
+ * <p>Errors encountered during uninstallation will throw an {@link IOException}.
+ */
+ public boolean uninstall() throws IOException {
+ Slog.i(logTag, "Uninstalling time zone update");
+
+ // Make sure we don't have a dir where we're going to move the currently installed data to.
+ if (oldTzDataDir.exists()) {
+ // If we can't remove this, an exception is thrown and we don't continue.
+ FileUtils.deleteRecursive(oldTzDataDir);
+ }
+
+ if (!currentTzDataDir.exists()) {
+ Slog.i(logTag, "Nothing to uninstall at " + currentTzDataDir);
+ return false;
+ }
+
+ try {
+ Slog.i(logTag, "Moving " + currentTzDataDir + " to " + oldTzDataDir);
+ // Move currentTzDataDir out of the way in one operation so we can't partially delete
+ // the contents, which would leave a partial install.
+ FileUtils.rename(currentTzDataDir, oldTzDataDir);
+ return true;
+ } finally {
+ // Do our best to delete the now uninstalled timezone data.
+ deleteBestEffort(oldTzDataDir);
}
}
@@ -109,11 +160,10 @@
}
}
- private File unpackBundle(byte[] content, File targetDir) throws IOException {
+ private void unpackBundle(byte[] content, File targetDir) throws IOException {
Slog.i(logTag, "Unpacking update content to: " + targetDir);
ConfigBundle bundle = new ConfigBundle(content);
bundle.extractTo(targetDir);
- return targetDir;
}
private boolean checkBundleFilesExist(File unpackedContentDir) throws IOException {
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TzDataBundleInstallerTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TzDataBundleInstallerTest.java
index 4c189e0..b55a257 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/TzDataBundleInstallerTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/TzDataBundleInstallerTest.java
@@ -163,7 +163,7 @@
* Tests that an update will be unpacked even if there is a partial update from a previous run.
*/
public void testInstallWithWorkingDir() throws Exception {
- File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ File workingDir = installer.getWorkingDir();
assertTrue(workingDir.mkdir());
createFile(new File(workingDir, "myFile"));
@@ -176,7 +176,7 @@
* Tests that a bundle without a bundle version file will be rejected.
*/
public void testInstallWithMissingBundleVersionFile() throws Exception {
- File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ File workingDir = installer.getWorkingDir();
assertTrue(workingDir.mkdir());
ConfigBundle tzData = createTzDataBundleWithoutFormatVersionFile(NEW_RULES_VERSION);
@@ -214,14 +214,35 @@
* Tests that a bundle with an incorrect bundle version will be rejected.
*/
public void testInstallWithInvalidBundleVersionFile() throws Exception {
- File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
- assertTrue(workingDir.mkdir());
-
ConfigBundle tzData = createTzDataBundleWithInvalidBundleVersion(NEW_RULES_VERSION);
assertFalse(installer.install(tzData.getBundleBytes()));
assertNoContentInstalled();
}
+ public void testUninstall_noExistingDataBundle() throws Exception {
+ assertFalse(installer.uninstall());
+ assertNoContentInstalled();
+ }
+
+ public void testUninstall_existingDataBundle() throws Exception {
+ File currentDataDir = installer.getCurrentTzDataDir();
+ assertTrue(currentDataDir.mkdir());
+
+ assertTrue(installer.uninstall());
+ assertNoContentInstalled();
+ }
+
+ public void testUninstall_oldDirsAlreadyExists() throws Exception {
+ File oldTzDataDir = installer.getOldTzDataDir();
+ assertTrue(oldTzDataDir.mkdir());
+
+ File currentDataDir = installer.getCurrentTzDataDir();
+ assertTrue(currentDataDir.mkdir());
+
+ assertTrue(installer.uninstall());
+ assertNoContentInstalled();
+ }
+
private ConfigBundle createTzDataBundleWithInvalidBundleVersion(String tzDataVersion)
throws IOException {
@@ -278,8 +299,7 @@
private void assertTzDataInstalled(ConfigBundle expectedTzData) throws Exception {
assertTrue(testInstallDir.exists());
- File currentTzDataDir =
- new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME);
+ File currentTzDataDir = installer.getCurrentTzDataDir();
assertTrue(currentTzDataDir.exists());
File bundleVersionFile = new File(currentTzDataDir,
@@ -297,19 +317,19 @@
assertTrue(icuFile.exists());
// Also check no working directory is left lying around.
- File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ File workingDir = installer.getWorkingDir();
assertFalse(workingDir.exists());
}
private void assertNoContentInstalled() {
- File currentTzDataDir = new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME);
+ File currentTzDataDir = installer.getCurrentTzDataDir();
assertFalse(currentTzDataDir.exists());
// Also check no working directories are left lying around.
- File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME);
+ File workingDir = installer.getWorkingDir();
assertFalse(workingDir.exists());
- File oldDataDir = new File(testInstallDir, TzDataBundleInstaller.OLD_TZ_DATA_DIR_NAME);
+ File oldDataDir = installer.getOldTzDataDir();
assertFalse(oldDataDir.exists());
}