Add access checks to Method and Field reflection.

Art side of this change. Has a corresponding libcore change.

Bug: 13620925
Change-Id: Ie67f802a2a400e8212b489b9a261b7028422d8ba
diff --git a/test/046-reflect/expected.txt b/test/046-reflect/expected.txt
index fcfaf2f..55b0dbe 100644
--- a/test/046-reflect/expected.txt
+++ b/test/046-reflect/expected.txt
@@ -81,7 +81,8 @@
  Field type is int
  Access flags are 0x11
   cantTouchThis is 77
-  cantTouchThis is now 99
+  as expected: set-final throws exception
+  cantTouchThis is still 77
   public final int Target.cantTouchThis accessible=false
   public final int Target.cantTouchThis accessible=true
   cantTouchThis is now 87
diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java
index dfb0d8f..d60fcb4 100644
--- a/test/046-reflect/src/Main.java
+++ b/test/046-reflect/src/Main.java
@@ -335,11 +335,12 @@
             System.out.println("  cantTouchThis is " + intVal);
             try {
                 field.setInt(instance, 99);
+                System.out.println("ERROR: set-final did not throw exception");
             } catch (IllegalAccessException iae) {
-                System.out.println("ERROR: set-final failed");
+                System.out.println("  as expected: set-final throws exception");
             }
             intVal = field.getInt(instance);
-            System.out.println("  cantTouchThis is now " + intVal);
+            System.out.println("  cantTouchThis is still " + intVal);
 
             System.out.println("  " + field + " accessible=" + field.isAccessible());
             field.setAccessible(true);
diff --git a/test/064-field-access/src/Main.java b/test/064-field-access/src/Main.java
index 3b9a475..c9b93ba 100644
--- a/test/064-field-access/src/Main.java
+++ b/test/064-field-access/src/Main.java
@@ -16,6 +16,7 @@
 
 import other.PublicClass;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 
 /*
  * Test field access through reflection.
@@ -192,6 +193,11 @@
   /* package */ static float samePackagePackageFloatStaticField = 63.0f;
   /* package */ static double samePackagePackageDoubleStaticField = 64.0;
   /* package */ static Object samePackagePackageObjectStaticField = "65";
+
+  public void samePublicMethod() { }
+  protected void sameProtectedMethod() { }
+  private void samePrivateMethod() { }
+  /* package */ void samePackageMethod() { }
 }
 
 /*
@@ -510,23 +516,32 @@
     for (int round = 0; round < 3; round++) {
       Object validInst;
       Field[] fields;
+      Method[] methods;
       boolean same_package = false;
+      boolean protected_class = false;
       switch (round) {
         case 0:
           validInst = new SamePackage();
           fields = SamePackage.class.getDeclaredFields();
           check(fields.length == 72);
+          methods = SamePackage.class.getDeclaredMethods();
+          check(methods.length == 4);
           same_package = true;
           break;
         case 1:
           validInst = new PublicClass();
           fields = PublicClass.class.getDeclaredFields();
           check(fields.length == 72);
+          methods = PublicClass.class.getDeclaredMethods();
+          check(methods.length == 4);
           break;
         default:
           validInst = new PublicClass();
           fields = PublicClass.class.getSuperclass().getDeclaredFields();
           check(fields.length == 72);
+          methods = PublicClass.class.getSuperclass().getDeclaredMethods();
+          check(methods.length == 4);
+          protected_class = true;
           break;
       }
       for (Field f : fields) {
@@ -540,16 +555,15 @@
         // Check access or lack of to field.
         Class<?> subClassAccessExceptionClass = null;
         if (f.getName().contains("Private") ||
-            (!same_package && f.getName().contains("Package"))) {
-          // ART deliberately doesn't throw IllegalAccessException.
-          // subClassAccessExceptionClass = IllegalAccessException.class;
+            (!same_package && f.getName().contains("Package")) ||
+            (!same_package && f.getName().contains("Protected"))) {
+          subClassAccessExceptionClass = IllegalAccessException.class;
         }
         Class<?> mainClassAccessExceptionClass = null;
         if (f.getName().contains("Private") ||
             (!same_package && f.getName().contains("Package")) ||
             (!same_package && f.getName().contains("Protected"))) {
-          // ART deliberately doesn't throw IllegalAccessException.
-          // mainClassAccessExceptionClass = IllegalAccessException.class;
+          mainClassAccessExceptionClass = IllegalAccessException.class;
         }
 
         this.getValue(f, validInst, typeChar, subClassAccessExceptionClass);
@@ -588,6 +602,16 @@
           }
         }
       }
+
+      for (Method m : methods) {
+        Class<?> subClassAccessExceptionClass = null;
+        if (protected_class || m.getName().contains("Private") ||
+            (!same_package && m.getName().contains("Package")) ||
+            (!same_package && m.getName().contains("Protected"))) {
+          subClassAccessExceptionClass = IllegalAccessException.class;
+        }
+        this.invoke(m, validInst, subClassAccessExceptionClass);
+      }
     }
     System.out.println("good");
   }
@@ -598,7 +622,6 @@
    */
   public Object getValue(Field field, Object obj, char type,
       Class expectedException) {
-
     Object result = null;
     try {
       switch (type) {
@@ -657,4 +680,29 @@
 
     return result;
   }
+
+  public Object invoke(Method method, Object obj, Class expectedException) {
+    Object result = null;
+    try {
+      result = method.invoke(obj);
+      /* success; expected? */
+      if (expectedException != null) {
+        System.err.println("ERROR: call succeeded for method " + method + "', was expecting " +
+                           expectedException);
+        Thread.dumpStack();
+      }
+    } catch (Exception ex) {
+      if (expectedException == null) {
+        System.err.println("ERROR: call failed unexpectedly: " + ex.getClass());
+        ex.printStackTrace();
+      } else {
+        if (!expectedException.equals(ex.getClass())) {
+          System.err.println("ERROR: incorrect exception: wanted " + expectedException.getName() +
+                             ", got " + ex.getClass());
+          ex.printStackTrace();
+        }
+      }
+    }
+    return result;
+  }
 }
diff --git a/test/064-field-access/src/other/ProtectedClass.java b/test/064-field-access/src/other/ProtectedClass.java
index 779aa1d..756c97f 100644
--- a/test/064-field-access/src/other/ProtectedClass.java
+++ b/test/064-field-access/src/other/ProtectedClass.java
@@ -97,4 +97,10 @@
  /* package */ static float otherProtectedClassPackageFloatStaticField = 63.0f;
  /* package */ static double otherProtectedClassPackageDoubleStaticField = 64.0;
  /* package */ static Object otherProtectedClassPackageObjectStaticField = "65";
+
+    public void otherPublicMethod() { }
+    protected void otherProtectedMethod() { }
+    private void otherPrivateMethod() { }
+    /* package */ void otherPackageMethod() { }
+
 }
diff --git a/test/064-field-access/src/other/PublicClass.java b/test/064-field-access/src/other/PublicClass.java
index 1653973..dbcb4fd 100644
--- a/test/064-field-access/src/other/PublicClass.java
+++ b/test/064-field-access/src/other/PublicClass.java
@@ -97,4 +97,9 @@
  /* package */ static float otherPublicClassPackageFloatStaticField = -63.0f;
  /* package */ static double otherPublicClassPackageDoubleStaticField = -64.0;
  /* package */ static Object otherPublicClassPackageObjectStaticField = "-65";
+
+    public void otherPublicMethod() { }
+    protected void otherProtectedMethod() { }
+    private void otherPrivateMethod() { }
+    /* package */ void otherPackageMethod() { }
 }
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
index 3d87ebc..bed0689 100644
--- a/test/100-reflect2/expected.txt
+++ b/test/100-reflect2/expected.txt
@@ -22,10 +22,7 @@
 30
 62
 14
-java.lang.IllegalArgumentException: Invalid primitive conversion from int to short
-	at java.lang.reflect.Field.set(Native Method)
-	at Main.testFieldReflection(Main.java:121)
-	at Main.main(Main.java:269)
+got expected IllegalArgumentException
 true (class java.lang.Boolean)
 6 (class java.lang.Byte)
 z (class java.lang.Character)
@@ -66,12 +63,6 @@
 true 0 1 2.0  hello world 3.0 4 5 6
 null (null)
 []
-java.lang.reflect.InvocationTargetException
-	at java.lang.reflect.Method.invoke(Native Method)
-	at Main.testMethodReflection(Main.java:210)
-	at Main.main(Main.java:270)
-Caused by: java.lang.ArithmeticException: surprise!
-	at Main.thrower(Main.java:218)
-	... 3 more
+got expected InvocationTargetException
  (class java.lang.String)
 yz (class java.lang.String)
diff --git a/test/100-reflect2/src/Main.java b/test/100-reflect2/src/Main.java
index 0404591..0cc1488 100644
--- a/test/100-reflect2/src/Main.java
+++ b/test/100-reflect2/src/Main.java
@@ -119,8 +119,9 @@
     try {
       f = Main.class.getDeclaredField("s");
       f.set(null, Integer.valueOf(14));
+      System.out.println("************* should have thrown!");
     } catch (IllegalArgumentException expected) {
-      expected.printStackTrace();
+      System.out.println("got expected IllegalArgumentException");
     }
 
     f = Main.class.getDeclaredField("z");
@@ -209,8 +210,8 @@
       System.out.println(Arrays.toString(m.getParameterTypes()));
       show(m.invoke(null));
       System.out.println("************* should have thrown!");
-    } catch (Exception expected) {
-      expected.printStackTrace();
+    } catch (InvocationTargetException expected) {
+      System.out.println("got expected InvocationTargetException");
     }
   }