Merge "Add a test to confirm that TZ data is in sync"
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index d766385..37b1d7d 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -55,6 +55,7 @@
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import libcore.reflect.AnnotationAccess;
 import libcore.reflect.GenericSignatureParser;
@@ -881,18 +882,7 @@
      * @throws NoSuchFieldException if the requested field can not be found.
      * @see #getField(String)
      */
-    public Field getDeclaredField(String name) throws NoSuchFieldException {
-        if (name == null) {
-            throw new NullPointerException("name == null");
-        }
-        Field result = getDeclaredFieldInternal(name);
-        if (result == null) {
-            throw new NoSuchFieldException(name);
-        } else {
-            result.getType();  // Throw NoClassDefFoundError if type cannot be resolved.
-        }
-        return result;
-    }
+    public native Field getDeclaredField(String name) throws NoSuchFieldException;
 
     /**
      * Returns an array containing {@code Field} objects for all fields declared
@@ -902,17 +892,7 @@
      *
      * @see #getFields()
      */
-    public Field[] getDeclaredFields() {
-        int initial_size = sFields == null ? 0 : sFields.length;
-        initial_size += iFields == null ? 0 : iFields.length;
-        ArrayList<Field> fields = new ArrayList(initial_size);
-        getDeclaredFieldsUnchecked(false, fields);
-        Field[] result = fields.toArray(new Field[fields.size()]);
-        for (Field f : result) {
-            f.getType();  // Throw NoClassDefFoundError if type cannot be resolved.
-        }
-        return result;
-    }
+    public native Field[] getDeclaredFields();
 
     /**
      * Populates a list of fields without performing any security or type
@@ -922,66 +902,18 @@
      * @param fields A list to populate with declared fields.
      * @hide
      */
-    public void getDeclaredFieldsUnchecked(boolean publicOnly, List<Field> fields) {
-        if (iFields != null) {
-            for (ArtField f : iFields) {
-                if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
-                    fields.add(new Field(f));
-                }
-            }
-        }
-        if (sFields != null) {
-            for (ArtField f : sFields) {
-                if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
-                    fields.add(new Field(f));
-                }
-            }
-        }
-    }
+    public native Field[] getDeclaredFieldsUnchecked(boolean publicOnly);
 
     /**
      * Returns the field if it is defined by this class; null otherwise. This
      * may return a non-public member.
      */
-    private Field getDeclaredFieldInternal(String name) {
-
-        if (iFields != null) {
-            final ArtField matched = findByName(name, iFields);
-            if (matched != null) {
-                return new Field(matched);
-            }
-        }
-        if (sFields != null) {
-            final ArtField matched = findByName(name, sFields);
-            if (matched != null) {
-                return new Field(matched);
-            }
-        }
-
-        return null;
-    }
+    private native Field getDeclaredFieldInternal(String name);
 
     /**
-     * Performs a binary search through {@code fields} for a field whose name
-     * is {@code name}. Returns {@code null} if no matching field exists.
+     * Returns the subset of getDeclaredFields which are public.
      */
-    private static ArtField findByName(String name, ArtField[] fields) {
-        int low = 0, high = fields.length - 1;
-        while (low <= high) {
-            final int mid = (low + high) >>> 1;
-            final ArtField f = fields[mid];
-            final int result = f.getName().compareTo(name);
-            if (result < 0) {
-                low = mid + 1;
-            } else if (result == 0) {
-                return f;
-            } else {
-                high = mid - 1;
-            }
-        }
-
-        return null;
-    }
+    private native Field[] getPublicDeclaredFields();
 
     /**
      * Returns the class that this class is a member of, or {@code null} if this
@@ -1080,8 +1012,6 @@
         Field result = getPublicFieldRecursive(name);
         if (result == null) {
             throw new NoSuchFieldException(name);
-        } else {
-            result.getType();  // Throw NoClassDefFoundError if type cannot be resolved.
         }
         return result;
     }
@@ -1098,8 +1028,7 @@
         // search iftable which has a flattened and uniqued list of interfaces
         if (ifTable != null) {
             for (int i = 0; i < ifTable.length; i += 2) {
-                Class<?> ifc = (Class<?>) ifTable[i];
-                Field result = ifc.getPublicFieldRecursive(name);
+                Field result = ((Class<?>) ifTable[i]).getPublicFieldRecursive(name);
                 if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
                     return result;
                 }
@@ -1123,11 +1052,7 @@
     public Field[] getFields() {
         List<Field> fields = new ArrayList<Field>();
         getPublicFieldsRecursive(fields);
-        Field[] result = fields.toArray(new Field[fields.size()]);
-        for (Field f : result) {
-            f.getType();  // Throw NoClassDefFoundError if type cannot be resolved.
-        }
-        return result;
+        return fields.toArray(new Field[fields.size()]);
     }
 
     /**
@@ -1137,15 +1062,14 @@
     private void getPublicFieldsRecursive(List<Field> result) {
         // search superclasses
         for (Class<?> c = this; c != null; c = c.superClass) {
-            c.getDeclaredFieldsUnchecked(true, result);
+            Collections.addAll(result, c.getPublicDeclaredFields());
         }
 
         // search iftable which has a flattened and uniqued list of interfaces
         Object[] iftable = ifTable;
         if (iftable != null) {
             for (int i = 0; i < iftable.length; i += 2) {
-                Class<?> ifc = (Class<?>) iftable[i];
-                ifc.getDeclaredFieldsUnchecked(true, result);
+                Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
             }
         }
     }
diff --git a/libart/src/main/java/java/lang/reflect/AccessibleObject.java b/libart/src/main/java/java/lang/reflect/AccessibleObject.java
index a1e2743..f623880 100644
--- a/libart/src/main/java/java/lang/reflect/AccessibleObject.java
+++ b/libart/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -71,15 +71,8 @@
      * IllegalAccessExceptions}.
      */
     public void setAccessible(boolean flag) {
-        try {
-          if (equals(Class.class.getDeclaredConstructor())) {
-            throw new SecurityException("Can't make class constructor accessible");
-          }
-        } catch (NoSuchMethodException e) {
-          throw new AssertionError("Couldn't find class constructor");
-        }
         this.flag = flag;
-     }
+    }
 
     /**
      * Attempts to set the accessible flag for all objects in {@code objects}.
diff --git a/libart/src/main/java/java/lang/reflect/ArtField.java b/libart/src/main/java/java/lang/reflect/ArtField.java
index 6fdcdb2..1801862 100644
--- a/libart/src/main/java/java/lang/reflect/ArtField.java
+++ b/libart/src/main/java/java/lang/reflect/ArtField.java
@@ -51,46 +51,4 @@
      * Only created by art directly.
      */
     private ArtField() {}
-
-    public int getAccessFlags() {
-        return accessFlags;
-    }
-
-    int getDexFieldIndex() {
-        return fieldDexIndex;
-    }
-
-    int getOffset() {
-        return offset;
-    }
-
-    public String getName() {
-        if (fieldDexIndex == -1) {
-            // Proxy classes have 1 synthesized static field with no valid dex index
-            if (!declaringClass.isProxy()) {
-                throw new AssertionError();
-            }
-            return "throws";
-        }
-        Dex dex = declaringClass.getDex();
-        int nameIndex = dex.nameIndexFromFieldIndex(fieldDexIndex);
-        return declaringClass.getDexCacheString(dex, nameIndex);
-    }
-
-    Class<?> getDeclaringClass() {
-        return declaringClass;
-    }
-
-    Class<?> getType() {
-        if (fieldDexIndex == -1) {
-            // The type of the synthesized field in a Proxy class is Class[][]
-            if (!declaringClass.isProxy()) {
-                throw new AssertionError();
-            }
-            return Class[][].class;
-        }
-        Dex dex = declaringClass.getDex();
-        int typeIndex = dex.typeIndexFromFieldIndex(fieldDexIndex);
-        return declaringClass.getDexCacheType(dex, typeIndex);
-    }
 }
diff --git a/libart/src/main/java/java/lang/reflect/Constructor.java b/libart/src/main/java/java/lang/reflect/Constructor.java
index 2eb12b0..66ae143 100644
--- a/libart/src/main/java/java/lang/reflect/Constructor.java
+++ b/libart/src/main/java/java/lang/reflect/Constructor.java
@@ -330,4 +330,20 @@
 
         return result.toString();
     }
+
+    /**
+     * Attempts to set the accessible flag. Setting this to true prevents {@code
+     * IllegalAccessExceptions}.
+     */
+    public void setAccessible(boolean flag) {
+        Class<?> declaringClass = getDeclaringClass();
+        if (declaringClass == Class.class) {
+            throw new SecurityException("Can't make class constructor accessible");
+        } else if (declaringClass == Field.class) {
+            throw new SecurityException("Can't make field constructor accessible");
+        } else if (declaringClass == Method.class) {
+            throw new SecurityException("Can't make method constructor accessible");
+        }
+        super.setAccessible(flag);
+    }
 }
diff --git a/libart/src/main/java/java/lang/reflect/Field.java b/libart/src/main/java/java/lang/reflect/Field.java
index cad876b..37f2ad0 100644
--- a/libart/src/main/java/java/lang/reflect/Field.java
+++ b/libart/src/main/java/java/lang/reflect/Field.java
@@ -71,16 +71,13 @@
         }
     };
 
-    private final ArtField artField;
+    private int accessFlags;
+    private Class<?> declaringClass;
+    private int dexFieldIndex;
+    private int offset;
+    private Class<?> type;
 
-    /**
-     * @hide
-     */
-    public Field(ArtField artField) {
-        if (artField == null) {
-            throw new NullPointerException("artField == null");
-        }
-        this.artField = artField;
+    private Field() {
     }
 
     /**
@@ -91,7 +88,7 @@
      * @see Modifier
      */
     @Override public int getModifiers() {
-        return artField.getAccessFlags() & 0xffff;  // mask out bits not used by Java
+        return accessFlags & 0xffff;  // mask out bits not used by Java
     }
 
     /**
@@ -101,7 +98,7 @@
      *         false} otherwise
      */
     public boolean isEnumConstant() {
-        return (artField.getAccessFlags() & Modifier.ENUM) != 0;
+        return (accessFlags & Modifier.ENUM) != 0;
     }
 
     /**
@@ -110,7 +107,7 @@
      * @return {@code true} if this field is synthetic, {@code false} otherwise
      */
     @Override public boolean isSynthetic() {
-        return (artField.getAccessFlags() & Modifier.SYNTHETIC) != 0;
+        return (accessFlags & Modifier.SYNTHETIC) != 0;
     }
 
     /**
@@ -119,11 +116,20 @@
      * @return the name of this field
      */
     @Override public String getName() {
-        return artField.getName();
+        if (dexFieldIndex == -1) {
+            // Proxy classes have 1 synthesized static field with no valid dex index.
+            if (!declaringClass.isProxy()) {
+                throw new AssertionError();
+            }
+            return "throws";
+        }
+        Dex dex = declaringClass.getDex();
+        int nameIndex = dex.nameIndexFromFieldIndex(dexFieldIndex);
+        return declaringClass.getDexCacheString(dex, nameIndex);
     }
 
     @Override public Class<?> getDeclaringClass() {
-        return artField.getDeclaringClass();
+        return declaringClass;
     }
 
     /**
@@ -132,7 +138,7 @@
      * @return the type of this field
      */
     public Class<?> getType() {
-        return artField.getType();
+        return type;
     }
 
     /**
@@ -141,7 +147,7 @@
      * @hide
      */
     public int getDexFieldIndex() {
-        return artField.getDexFieldIndex();
+        return dexFieldIndex;
     }
 
     /**
@@ -150,7 +156,7 @@
      * @hide
      */
     public int getOffset() {
-        return artField.getOffset();
+        return offset;
     }
 
     /**
@@ -170,8 +176,10 @@
         if (!(other instanceof Field)) {
             return false;
         }
-        // exactly one instance of each member in this runtime
-        return this.artField == ((Field) other).artField;
+        // Given same declaring class and offset, it must be the same field since no two distinct
+        // fields can have the same offset.
+        Field field = (Field)other;
+        return this.declaringClass == field.declaringClass && this.offset == field.offset;
     }
 
     /**
@@ -277,11 +285,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public Object get(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return get(object, isAccessible());
-    }
-
-    private native Object get(Object object, boolean accessible)
+    public native Object get(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -307,12 +311,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public boolean getBoolean(Object object) throws IllegalAccessException,
-                                                    IllegalArgumentException {
-        return getBoolean(object, isAccessible());
-    }
-
-    private native boolean getBoolean(Object object, boolean accessible)
+    public native boolean getBoolean(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -338,11 +337,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public byte getByte(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getByte(object, isAccessible());
-    }
-
-    private native byte getByte(Object object, boolean accessible)
+    public native byte getByte(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -368,11 +363,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public char getChar(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getChar(object, isAccessible());
-    }
-
-    private native char getChar(Object object, boolean accessible)
+    public native char getChar(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -398,11 +389,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public double getDouble(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getDouble(object, isAccessible());
-    }
-
-    private native double getDouble(Object object, boolean accessible)
+    public native double getDouble(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -428,11 +415,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public float getFloat(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getFloat(object, isAccessible());
-    }
-
-    private native float getFloat(Object object, boolean accessible)
+    public native float getFloat(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -458,11 +441,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public int getInt(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getInt(object, isAccessible());
-    }
-
-    private native int getInt(Object object, boolean accessible)
+    public native int getInt(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -488,11 +467,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public long getLong(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getLong(object, isAccessible());
-    }
-
-    private native long getLong(Object object, boolean accessible)
+    public native long getLong(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -518,11 +493,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public short getShort(Object object) throws IllegalAccessException, IllegalArgumentException {
-        return getShort(object, isAccessible());
-    }
-
-    private native short getShort(Object object, boolean accessible)
+    public native short getShort(Object object)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -554,12 +525,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void set(Object object, Object value) throws IllegalAccessException,
-                                                        IllegalArgumentException {
-        set(object, value, isAccessible());
-    }
-
-    private native void set(Object object, Object value, boolean accessible)
+    public native void set(Object object, Object value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -590,12 +556,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setBoolean(Object object, boolean value) throws IllegalAccessException,
-                                                                IllegalArgumentException {
-        setBoolean(object, value, isAccessible());
-    }
-
-    private native void setBoolean(Object object, boolean value, boolean accessible)
+    public native void setBoolean(Object object, boolean value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -625,14 +586,8 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setByte(Object object, byte value) throws IllegalAccessException,
-                                                          IllegalArgumentException {
-        setByte(object, value, isAccessible());
-    }
-
-    private native void setByte(Object object, byte value, boolean accessible)
+    public native void setByte(Object object, byte value)
             throws IllegalAccessException, IllegalArgumentException;
-
     /**
      * Sets the value of the field in the specified object to the {@code char}
      * value. This reproduces the effect of {@code object.fieldName = value}
@@ -660,12 +615,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setChar(Object object, char value) throws IllegalAccessException,
-                                                          IllegalArgumentException {
-        setChar(object, value, isAccessible());
-    }
-
-    private native void setChar(Object object, char value, boolean accessible)
+    public native void setChar(Object object, char value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -695,12 +645,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setDouble(Object object, double value) throws IllegalAccessException,
-                                                              IllegalArgumentException {
-        setDouble(object, value, isAccessible());
-    }
-
-    private native void setDouble(Object object, double value, boolean accessible)
+    public native void setDouble(Object object, double value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -730,12 +675,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setFloat(Object object, float value) throws IllegalAccessException,
-                                                            IllegalArgumentException {
-        setFloat(object, value, isAccessible());
-    }
-
-    private native void setFloat(Object object, float value, boolean accessible)
+    public native void setFloat(Object object, float value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -765,12 +705,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setInt(Object object, int value) throws IllegalAccessException,
-                                                        IllegalArgumentException {
-        setInt(object, value, isAccessible());
-    }
-
-    private native void setInt(Object object, int value, boolean accessible)
+    public native void setInt(Object object, int value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -800,12 +735,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setLong(Object object, long value) throws IllegalAccessException,
-                                                          IllegalArgumentException {
-        setLong(object, value, isAccessible());
-    }
-
-    private native void setLong(Object object, long value, boolean accessible)
+    public native void setLong(Object object, long value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
@@ -835,12 +765,7 @@
      * @throws IllegalAccessException
      *             if this field is not accessible
      */
-    public void setShort(Object object, short value) throws IllegalAccessException,
-                                                            IllegalArgumentException {
-        setShort(object, value, isAccessible());
-    }
-
-    private native void setShort(Object object, short value, boolean accessible)
+    public native void setShort(Object object, short value)
             throws IllegalAccessException, IllegalArgumentException;
 
     /**
diff --git a/luni/src/main/java/javax/crypto/ExemptionMechanism.java b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
index c2d42e6..eede649 100644
--- a/luni/src/main/java/javax/crypto/ExemptionMechanism.java
+++ b/luni/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -361,9 +361,6 @@
         return len;
     }
 
-    /**
-     * Override to clear any key state in the instance.
-     */
     @Override protected void finalize() {
         try {
             super.finalize();
diff --git a/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
index 3c04525..d04e2ba 100644
--- a/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
+++ b/luni/src/test/java/libcore/net/NetworkSecurityPolicyTest.java
@@ -70,6 +70,33 @@
         assertEquals(true, NetworkSecurityPolicy.isCleartextTrafficPermitted());
     }
 
+    public void testCleartextTrafficPolicyWithHttpURLConnection() throws Exception {
+        // Assert that client transmits some data when cleartext traffic is permitted.
+        NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+        try (CapturingServerSocket server = new CapturingServerSocket()) {
+            URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+            try {
+                url.openConnection().getContent();
+                fail();
+            } catch (IOException expected) {
+            }
+            server.assertDataTransmittedByClient();
+        }
+
+        // Assert that client does not transmit any data when cleartext traffic is not permitted and
+        // that URLConnection.openConnection or getContent fail with an IOException.
+        NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+        try (CapturingServerSocket server = new CapturingServerSocket()) {
+            URL url = new URL("http://localhost:" + server.getPort() + "/test.txt");
+            try {
+                url.openConnection().getContent();
+                fail();
+            } catch (IOException expected) {
+            }
+            server.assertNoDataTransmittedByClient();
+        }
+    }
+
     public void testCleartextTrafficPolicyWithFtpURLConnection() throws Exception {
         // Assert that client transmits some data when cleartext traffic is permitted.
         NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
@@ -98,6 +125,33 @@
         }
     }
 
+    public void testCleartextTrafficPolicyWithJarHttpURLConnection() throws Exception {
+        // Assert that client transmits some data when cleartext traffic is permitted.
+        NetworkSecurityPolicy.setCleartextTrafficPermitted(true);
+        try (CapturingServerSocket server = new CapturingServerSocket()) {
+            URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+            try {
+                ((JarURLConnection) url.openConnection()).getManifest();
+                fail();
+            } catch (IOException expected) {
+            }
+            server.assertDataTransmittedByClient();
+        }
+
+        // Assert that client does not transmit any data when cleartext traffic is not permitted and
+        // that JarURLConnection.openConnection or getManifest fail with an IOException.
+        NetworkSecurityPolicy.setCleartextTrafficPermitted(false);
+        try (CapturingServerSocket server = new CapturingServerSocket()) {
+            URL url = new URL("jar:http://localhost:" + server.getPort() + "/test.jar!/");
+            try {
+                ((JarURLConnection) url.openConnection()).getManifest();
+                fail();
+            } catch (IOException expected) {
+            }
+            server.assertNoDataTransmittedByClient();
+        }
+    }
+
     public void testCleartextTrafficPolicyWithJarFtpURLConnection() throws Exception {
         // Assert that client transmits some data when cleartext traffic is permitted.
         NetworkSecurityPolicy.setCleartextTrafficPermitted(true);