Allow JNI AttachCurrentThread to fail if not enough stack.

Add unit tests and move JavaVM JNI tests into there own set of gtests.
Bug: 18330119

Change-Id: I0e93dff783b1f5d787b3084d24122883e14951a1
diff --git a/runtime/java_vm_ext_test.cc b/runtime/java_vm_ext_test.cc
new file mode 100644
index 0000000..60c6a5c
--- /dev/null
+++ b/runtime/java_vm_ext_test.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include "jni_internal.h"
+
+#include <pthread.h>
+
+#include "common_runtime_test.h"
+#include "java_vm_ext.h"
+#include "runtime.h"
+
+namespace art {
+
+class JavaVmExtTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+
+    vm_ = Runtime::Current()->GetJavaVM();
+  }
+
+
+  virtual void TearDown() OVERRIDE {
+    CommonRuntimeTest::TearDown();
+  }
+
+  JavaVMExt* vm_;
+};
+
+TEST_F(JavaVmExtTest, JNI_GetDefaultJavaVMInitArgs) {
+  jint err = JNI_GetDefaultJavaVMInitArgs(nullptr);
+  EXPECT_EQ(JNI_ERR, err);
+}
+
+TEST_F(JavaVmExtTest, JNI_GetCreatedJavaVMs) {
+  JavaVM* vms_buf[1];
+  jsize num_vms;
+  jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
+  EXPECT_EQ(JNI_OK, ok);
+  EXPECT_EQ(1, num_vms);
+  EXPECT_EQ(vms_buf[0], vm_);
+}
+
+static bool gSmallStack = false;
+static bool gAsDaemon = false;
+
+static void* attach_current_thread_callback(void* arg ATTRIBUTE_UNUSED) {
+  JavaVM* vms_buf[1];
+  jsize num_vms;
+  JNIEnv* env;
+  jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
+  EXPECT_EQ(JNI_OK, ok);
+  if (ok == JNI_OK) {
+    if (!gAsDaemon) {
+      ok = vms_buf[0]->AttachCurrentThread(&env, nullptr);
+    } else {
+      ok = vms_buf[0]->AttachCurrentThreadAsDaemon(&env, nullptr);
+    }
+    EXPECT_EQ(gSmallStack ? JNI_ERR : JNI_OK, ok);
+    if (ok == JNI_OK) {
+      ok = vms_buf[0]->DetachCurrentThread();
+      EXPECT_EQ(JNI_OK, ok);
+    }
+  }
+  return nullptr;
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThread) {
+  pthread_t pthread;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = false;
+  gAsDaemon = false;
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
+      nullptr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThreadAsDaemon) {
+  pthread_t pthread;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = false;
+  gAsDaemon = true;
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
+      nullptr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, AttachCurrentThread_SmallStack) {
+  pthread_t pthread;
+  pthread_attr_t attr;
+  const char* reason = __PRETTY_FUNCTION__;
+  gSmallStack = true;
+  gAsDaemon = false;
+  CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
+  CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, PTHREAD_STACK_MIN), reason);
+  CHECK_PTHREAD_CALL(pthread_create, (&pthread, &attr, attach_current_thread_callback,
+      nullptr), reason);
+  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
+  void* ret_val;
+  CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
+  EXPECT_EQ(ret_val, nullptr);
+}
+
+TEST_F(JavaVmExtTest, DetachCurrentThread) {
+  JNIEnv* env;
+  jint ok = vm_->AttachCurrentThread(&env, nullptr);
+  ASSERT_EQ(JNI_OK, ok);
+  ok = vm_->DetachCurrentThread();
+  EXPECT_EQ(JNI_OK, ok);
+
+  jint err = vm_->DetachCurrentThread();
+  EXPECT_EQ(JNI_ERR, err);
+}
+
+}  // namespace art