am 4aa9da3f: Merge "Build fix."

* commit '4aa9da3f32d8e97968f4a627e03f7fcf041270a7':
  Build fix.
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 5cebb63..5b5803d 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -98,6 +98,21 @@
   ]
 },
 {
+  description: "Some DecimalFormat tests fail, treating tests as broken while investigate further.",
+  bug: 12781028,
+  result: EXEC_FAILED,
+  names: [
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#testSerializationSelf",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatD",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDLjava_lang_StringBufferLjava_text_FieldPosition",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDLjava_lang_StringBufferLjava_text_FieldPosition_problem_cases",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatD_2",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatJLjava_lang_StringBufferLjava_text_FieldPosition",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatToCharacterIterator_very_large",
+      "org.apache.harmony.tests.java.text.DecimalFormatTest#test_format_minus_zero"
+  ]
+},
+{
   description: "Fails in CTS, passes in CoreTestRunner.",
   result: EXEC_FAILED,
   names: [
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index e0b4d38..0392a11 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1438,8 +1438,73 @@
   ]
 },
 {
+  description: "Known failures in klp-modular-dev branch being suppressed for dory / molly.",
+  bug: 14674275,
+  names: [
+    "libcore.java.lang.SystemTest#testArrayCopyConcurrentModification",
+    "libcore.java.lang.ref.FinalizeTest#testSystemRunFinalizationReturnsEvenIfQueueIsNonEmpty",
+    "libcore.java.lang.reflect.ClassLoaderReflectionTest#testConstructorsOfDifferentClassLoadersAreNotEqual",
+    "libcore.java.lang.reflect.ClassLoaderReflectionTest#testFieldsOfDifferentClassLoadersAreNotEqual",
+    "libcore.java.lang.reflect.MethodTest#testEqualMethodEqualsAndHashCode",
+    "libcore.java.lang.reflect.MethodTest#testHashCodeSpec",
+    "libcore.java.lang.reflect.ProxyTest#testDeclaredExceptionIntersectedByExactReturnTypes",
+    "libcore.java.lang.reflect.ProxyTest#testReturnTypeDoesNotSatisfyAllConstraintsWithLenientCaller",
+    "libcore.java.net.ConcurrentCloseTest#test_connect",
+    "libcore.java.net.ConcurrentCloseTest#test_connect_nonBlocking",
+    "libcore.java.net.ConcurrentCloseTest#test_connect_timeout",
+    "libcore.java.net.InetAddressTest#test_isReachable",
+    "libcore.java.net.OldCookieHandlerTest#test_get_put",
+    "libcore.java.net.OldSocketTest#test_ConstructorLjava_lang_StringILjava_net_InetAddressI2",
+    "libcore.java.net.OldSocketTest#test_connectLjava_net_SocketAddressI",
+    "libcore.java.net.URLConnectionTest#testConnectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache",
+    "libcore.java.util.prefs.OldFilePreferencesImplTest#testSystemChildNodes",
+    "libcore.java.util.prefs.OldNodeChangeEventTest#testGetChild",
+    "libcore.java.util.prefs.OldNodeChangeEventTest#testGetParent",
+    "org.apache.harmony.luni.tests.java.net.URLConnectionTest#test_getLastModified",
+    "org.apache.harmony.tests.java.io.SerializationStressTest4#test_writeObject_Proxy",
+    "org.apache.harmony.tests.java.lang.RuntimeTest#test_gc",
+    "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_removeJ",
+    "org.apache.harmony.tests.java.lang.reflect.FieldTest#testProtectedFieldAccess",
+    "org.apache.harmony.tests.java.lang.reflect.ProxyTest#test_ProxyClass_withParentAndSubInThrowList",
+    "org.apache.harmony.tests.java.net.DatagramSocketTest#test_setBroadcastZ",
+    "org.apache.harmony.tests.java.net.JarURLConnectionTest#test_getURLEncodedEntry",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv6",
+    "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setNetworkInterfaceLjava_net_NetworkInterface_IPv4",
+    "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition",
+    "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parseLjava_lang_StringLjava_text_ParsePosition",
+    "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testGetContentType",
+    "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testGetInputStream",
+    "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testHeaderFunctions",
+    "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testHeader_BoundaryCheck"
+  ]
+},
+{
   description: "Known failure in GregorianCalendarTest",
   bug: 12778197,
   name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
+},
+{
+  description: "Environment specific Console test suppressed for dory / molly",
+  bug: 12491103,
+  name: "org.apache.harmony.tests.java.io.ConsoleTest#test_readPassword_LString_LObject"
+},
+{
+  description: "Suppression of a test that proves there is a known bug with Matcher",
+  bug: 14865710,
+  name: "org.apache.harmony.tests.java.util.ScannerParseLargeFileBenchmarkTest#testParseLargeFile"
 }
 ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index 959f83c..a029a51 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -349,8 +349,9 @@
         } catch (IllegalArgumentException e) {
             // correct
         }
-        // tests nowhere
-        ia = Inet4Address.getByName("1.1.1.1");
+        // tests unreachable address. 192.0.2.1 is reserved by RFC 5737
+        // and should not be used outside of example code / docs.
+        ia = Inet4Address.getByName("192.0.2.1");
         assertFalse(ia.isReachable(1000));
         assertFalse(ia.isReachable(null, 0, 1000));
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 49e7868..740340e 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -25,6 +25,8 @@
 import java.net.URL;
 import java.security.Permission;
 import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.Vector;
 import java.util.jar.Attributes;
@@ -92,6 +94,10 @@
 
     private final String emptyEntry3 = "svgunit.js";
 
+    private static final String VALID_CHAIN_JAR = "hyts_signed_validChain.jar";
+
+    private static final String INVALID_CHAIN_JAR = "hyts_signed_invalidChain.jar";
+
     private File resources;
 
     // custom security manager
@@ -641,6 +647,70 @@
                         + jarName + "\"", foundCerts);
     }
 
+    private Certificate[] getSignedJarCerts(String jarName, boolean chainCheck) throws Exception {
+        Support_Resources.copyFile(resources, null, jarName);
+
+        File file = new File(resources, jarName);
+        Certificate[] foundCerts = null;
+
+        JarFile jarFile = new JarFile(file, true, ZipFile.OPEN_READ, chainCheck);
+        try {
+
+            Enumeration<JarEntry> e = jarFile.entries();
+            while (e.hasMoreElements()) {
+                JarEntry entry = e.nextElement();
+                InputStream is = jarFile.getInputStream(entry);
+                // Skip bytes because we have to read the entire file for it to read signatures.
+                is.skip(entry.getSize());
+                is.close();
+                Certificate[] certs = entry.getCertificates();
+                if (certs != null && certs.length > 0) {
+                    foundCerts = certs;
+                    break;
+                }
+            }
+        } finally {
+            jarFile.close();
+        }
+
+        return foundCerts;
+    }
+
+    public void testJarFile_Signed_ValidChain_NoCheck() throws Exception {
+        Certificate[] certs = getSignedJarCerts(VALID_CHAIN_JAR, false);
+        assertNotNull(certs);
+        assertEquals(Arrays.deepToString(certs), 3, certs.length);
+        assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
+        assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
+    }
+
+    public void testJarFile_Signed_ValidChain_Check() throws Exception {
+        Certificate[] certs = getSignedJarCerts(VALID_CHAIN_JAR, true);
+        assertNotNull(certs);
+        assertEquals(Arrays.deepToString(certs), 3, certs.length);
+        assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
+        assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
+    }
+
+    public void testJarFile_Signed_InvalidChain_NoCheck() throws Exception {
+        Certificate[] certs = getSignedJarCerts(INVALID_CHAIN_JAR, false);
+        assertNotNull(certs);
+        assertEquals(Arrays.deepToString(certs), 3, certs.length);
+        assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
+        assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
+    }
+
+    public void testJarFile_Signed_InvalidChain_Check() throws Exception {
+        Certificate[] certs = getSignedJarCerts(INVALID_CHAIN_JAR, true);
+        assertNotNull(certs);
+        assertEquals(Arrays.deepToString(certs), 2, certs.length);
+        assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
+    }
+
     /*
      * The jar created by 1.4 which does not provide a
      * algorithm-Digest-Manifest-Main-Attributes entry in .SF file.
diff --git a/luni/src/main/java/java/lang/System.java b/luni/src/main/java/java/lang/System.java
index 185701e..6fc35da 100644
--- a/luni/src/main/java/java/lang/System.java
+++ b/luni/src/main/java/java/lang/System.java
@@ -356,6 +356,11 @@
         }
         p.put("java.home", javaHome);
 
+        String ldLibraryPath = getenv("LD_LIBRARY_PATH");
+        if (ldLibraryPath != null) {
+            p.put("java.library.path", ldLibraryPath);
+        }
+
         p.put("java.specification.name", "Dalvik Core Library");
         p.put("java.specification.vendor", projectName);
         p.put("java.specification.version", "0.9");
diff --git a/luni/src/main/java/java/util/jar/JarFile.java b/luni/src/main/java/java/util/jar/JarFile.java
index 6b147f6..a089019 100644
--- a/luni/src/main/java/java/util/jar/JarFile.java
+++ b/luni/src/main/java/java/util/jar/JarFile.java
@@ -196,6 +196,16 @@
      *             If the file cannot be read.
      */
     public JarFile(File file, boolean verify, int mode) throws IOException {
+        this(file, verify, mode, false);
+    }
+
+    /**
+     * See previous constructor for other parameter definitions.
+     * @param chainCheck
+     *            whether or not to check certificate chain signatures
+     * @hide
+     */
+    public JarFile(File file, boolean verify, int mode, boolean chainCheck) throws IOException {
         super(file, mode);
 
         // Step 1: Scan the central directory for meta entries (MANIFEST.mf
@@ -215,7 +225,7 @@
             // We create the manifest straight away, so that we can create
             // the jar verifier as well.
             manifest = new Manifest(metaEntries.get(MANIFEST_NAME), true);
-            verifier = new JarVerifier(getName(), manifest, metaEntries);
+            verifier = new JarVerifier(getName(), manifest, metaEntries, chainCheck);
         } else {
             verifier = null;
             manifestBytes = metaEntries.get(MANIFEST_NAME);
@@ -247,7 +257,17 @@
      *             If file cannot be opened or read.
      */
     public JarFile(String filename, boolean verify) throws IOException {
-        this(new File(filename), verify, ZipFile.OPEN_READ);
+        this(filename, verify, false);
+    }
+
+    /**
+     * See previous constructor for other parameter definitions.
+     * @param chainCheck
+     *            whether or not to check certificate chain signatures
+     * @hide
+     */
+    public JarFile(String filename, boolean verify, boolean chainCheck) throws IOException {
+        this(new File(filename), verify, ZipFile.OPEN_READ, chainCheck);
     }
 
     /**
diff --git a/luni/src/main/java/java/util/jar/JarVerifier.java b/luni/src/main/java/java/util/jar/JarVerifier.java
index c545a02..f78cbe8 100644
--- a/luni/src/main/java/java/util/jar/JarVerifier.java
+++ b/luni/src/main/java/java/util/jar/JarVerifier.java
@@ -75,6 +75,9 @@
     private final Hashtable<String, Certificate[]> verifiedEntries =
             new Hashtable<String, Certificate[]>();
 
+    /** Whether or not to check certificate chain signatures. */
+    private final boolean chainCheck;
+
     /**
      * Stores and a hash and a message digest and verifies that massage digest
      * matches the hash.
@@ -147,16 +150,27 @@
     }
 
     /**
+     * Convenience constructor for backward compatibility.
+     */
+    JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries) {
+        this(name, manifest, metaEntries, false);
+    }
+
+    /**
      * Constructs and returns a new instance of {@code JarVerifier}.
      *
      * @param name
      *            the name of the JAR file being verified.
+     * @param chainCheck
+     *            whether to check the certificate chain signatures
      */
-    JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries) {
+    JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries,
+            boolean chainCheck) {
         jarName = name;
         this.manifest = manifest;
         this.metaEntries = metaEntries;
         this.mainAttributesEnd = manifest.getMainAttributesEnd();
+        this.chainCheck = chainCheck;
     }
 
     /**
@@ -295,7 +309,15 @@
         try {
             Certificate[] signerCertChain = JarUtils.verifySignature(
                     new ByteArrayInputStream(sfBytes),
-                    new ByteArrayInputStream(sBlockBytes));
+                    new ByteArrayInputStream(sBlockBytes),
+                    chainCheck);
+            /*
+             * Recursive call in loading security provider related class which
+             * is in a signed JAR.
+             */
+            if (metaEntries == null) {
+                return;
+            }
             if (signerCertChain != null) {
                 certificates.put(signatureFile, signerCertChain);
             }
diff --git a/luni/src/main/java/java/util/jar/StrictJarFile.java b/luni/src/main/java/java/util/jar/StrictJarFile.java
index fa175d8..80b4fe9 100644
--- a/luni/src/main/java/java/util/jar/StrictJarFile.java
+++ b/luni/src/main/java/java/util/jar/StrictJarFile.java
@@ -63,7 +63,7 @@
             // or manifests, so it's best to throw as early as possible.
             HashMap<String, byte[]> metaEntries = getMetaEntries();
             this.manifest = new Manifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
-            this.verifier = new JarVerifier(fileName, manifest, metaEntries);
+            this.verifier = new JarVerifier(fileName, manifest, metaEntries, true);
 
             isSigned = verifier.readCertificates() && verifier.isSignedJar();
         } catch (IOException ioe) {
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index d11c8dd..b9056353 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -54,18 +54,27 @@
         new int[] {1, 2, 840, 113549, 1, 9, 4};
 
     /**
+     * @see #verifySignature(InputStream, InputStream, boolean)
+     */
+    public static Certificate[] verifySignature(InputStream signature, InputStream signatureBlock)
+            throws IOException, GeneralSecurityException {
+        return verifySignature(signature, signatureBlock, false);
+    }
+
+    /**
      * This method handle all the work with  PKCS7, ASN1 encoding, signature verifying,
      * and certification path building.
      * See also PKCS #7: Cryptographic Message Syntax Standard:
      * http://www.ietf.org/rfc/rfc2315.txt
      * @param signature - the input stream of signature file to be verified
      * @param signatureBlock - the input stream of corresponding signature block file
+     * @param chainCheck - whether to validate certificate chain signatures
      * @return array of certificates used to verify the signature file
      * @throws IOException - if some errors occurs during reading from the stream
      * @throws GeneralSecurityException - if signature verification process fails
      */
     public static Certificate[] verifySignature(InputStream signature, InputStream
-            signatureBlock) throws IOException, GeneralSecurityException {
+            signatureBlock, boolean chainCheck) throws IOException, GeneralSecurityException {
 
         BerInputStream bis = new BerInputStream(signatureBlock);
         ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);
@@ -223,11 +232,11 @@
             throw new SecurityException("Incorrect signature");
         }
 
-        return createChain(certs[issuerSertIndex], certs);
+        return createChain(certs[issuerSertIndex], certs, chainCheck);
     }
 
     private static X509Certificate[] createChain(X509Certificate signer,
-            X509Certificate[] candidates) {
+            X509Certificate[] candidates, boolean chainCheck) {
         Principal issuer = signer.getIssuerDN();
 
         // Signer is self-signed
@@ -239,10 +248,11 @@
         chain.add(0, signer);
 
         X509Certificate issuerCert;
+        X509Certificate subjectCert = signer;
         int count = 1;
         while (true) {
-            issuerCert = findCert(issuer, candidates);
-            if (issuerCert == null) {
+            issuerCert = findCert(issuer, candidates, subjectCert, chainCheck);
+            if( issuerCert == null) {
                 break;
             }
             chain.add(issuerCert);
@@ -251,13 +261,22 @@
             if (issuerCert.getSubjectDN().equals(issuer)) {
                 break;
             }
+            subjectCert = issuerCert;
         }
         return chain.toArray(new X509Certificate[count]);
     }
 
-    private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) {
+    private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates,
+            X509Certificate subjectCert, boolean chainCheck) {
         for (int i = 0; i < candidates.length; i++) {
             if (issuer.equals(candidates[i].getSubjectDN())) {
+                if (chainCheck) {
+                    try {
+                        subjectCert.verify(candidates[i].getPublicKey());
+                    } catch (Exception e) {
+                        continue;
+                    }
+                }
                 return candidates[i];
             }
         }
diff --git a/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar b/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar
new file mode 100644
index 0000000..23d7ae8
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar
Binary files differ
diff --git a/support/src/test/java/tests/resources/hyts_signed_validChain.jar b/support/src/test/java/tests/resources/hyts_signed_validChain.jar
new file mode 100644
index 0000000..d1f4c56
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_validChain.jar
Binary files differ