Fix reflection access check for attached native threads.

Bug: 15539150
Change-Id: Ie580cad1c0169d550162bcc878b07643259323c4
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 89cdb4d..fe5e104 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -815,6 +815,10 @@
 bool VerifyAccess(mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags) {
   NthCallerVisitor visitor(Thread::Current(), 2);
   visitor.WalkStack();
+  if (UNLIKELY(visitor.caller == nullptr)) {
+    // The caller is an attached native thread.
+    return (access_flags & kAccPublic) != 0;
+  }
   mirror::Class* caller_class = visitor.caller->GetDeclaringClass();
 
   if (((access_flags & kAccPublic) != 0) || (caller_class == declaring_class)) {
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
index 3c4ed35..33418a9 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -21,6 +21,7 @@
         System.loadLibrary("arttest");
         testFindClassOnAttachedNativeThread();
         testFindFieldOnAttachedNativeThread();
+        testReflectFieldGetFromAttachedNativeThreadNative();
         testCallStaticVoidMethodOnSubClass();
         testGetMirandaMethod();
         testZeroLengthByteBuffers();
@@ -34,6 +35,10 @@
 
     private static boolean testFindFieldOnAttachedNativeThreadField;
 
+    private static native void testReflectFieldGetFromAttachedNativeThreadNative();
+
+    public static boolean testReflectFieldGetFromAttachedNativeThreadField;
+
     private static void testFindFieldOnAttachedNativeThread() {
       testFindFieldOnAttachedNativeThreadNative();
       if (!testFindFieldOnAttachedNativeThreadField) {
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index 024ba53..36cad72 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -103,6 +103,66 @@
   assert(pthread_join_result == 0);
 }
 
+static void* testReflectFieldGetFromAttachedNativeThread(void*) {
+  assert(jvm != NULL);
+
+  JNIEnv* env = NULL;
+  JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL };
+  int attach_result = jvm->AttachCurrentThread(&env, &args);
+  assert(attach_result == 0);
+
+  jclass clazz = env->FindClass("JniTest");
+  assert(clazz != NULL);
+  assert(!env->ExceptionCheck());
+
+  jclass class_clazz = env->FindClass("java/lang/Class");
+  assert(class_clazz != NULL);
+  assert(!env->ExceptionCheck());
+
+  jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField",
+                                               "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
+  assert(getFieldMetodId != NULL);
+  assert(!env->ExceptionCheck());
+
+  jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField");
+  assert(field_name != NULL);
+  assert(!env->ExceptionCheck());
+
+  jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name);
+  assert(field != NULL);
+  assert(!env->ExceptionCheck());
+
+  jclass field_clazz = env->FindClass("java/lang/reflect/Field");
+  assert(field_clazz != NULL);
+  assert(!env->ExceptionCheck());
+
+  jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean",
+                                                 "(Ljava/lang/Object;)Z");
+  assert(getBooleanMetodId != NULL);
+  assert(!env->ExceptionCheck());
+
+  jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz);
+  assert(value == false);
+  assert(!env->ExceptionCheck());
+
+  int detach_result = jvm->DetachCurrentThread();
+  assert(detach_result == 0);
+  return NULL;
+}
+
+// http://b/15539150
+extern "C" JNIEXPORT void JNICALL Java_JniTest_testReflectFieldGetFromAttachedNativeThreadNative(
+    JNIEnv*, jclass) {
+  pthread_t pthread;
+  int pthread_create_result = pthread_create(&pthread,
+                                             NULL,
+                                             testReflectFieldGetFromAttachedNativeThread,
+                                             NULL);
+  assert(pthread_create_result == 0);
+  int pthread_join_result = pthread_join(pthread, NULL);
+  assert(pthread_join_result == 0);
+}
+
 
 // http://b/11243757
 extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,