189 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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/jni_internal.h"
 | |
| 
 | |
| #include <pthread.h>
 | |
| 
 | |
| #include "common_runtime_test.h"
 | |
| #include "gc/heap.h"
 | |
| #include "java_vm_ext.h"
 | |
| #include "runtime.h"
 | |
| 
 | |
| namespace art {
 | |
| 
 | |
| class JavaVmExtTest : public CommonRuntimeTest {
 | |
|  protected:
 | |
|   JavaVmExtTest() {
 | |
|     this->use_boot_image_ = true;  // Make the Runtime creation cheaper.
 | |
|   }
 | |
| 
 | |
|   void SetUp() override {
 | |
|     CommonRuntimeTest::SetUp();
 | |
| 
 | |
|     vm_ = Runtime::Current()->GetJavaVM();
 | |
|   }
 | |
| 
 | |
| 
 | |
|   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);
 | |
|     }
 | |
|     // TODO: Find a way to test with exact SMALL_STACK value, for which we would bail. The pthreads
 | |
|     //       spec says that the stack size argument is a lower bound, and bionic currently gives us
 | |
|     //       a chunk more on arm64.
 | |
|     if (!gSmallStack) {
 | |
|       EXPECT_EQ(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) {
 | |
|   TEST_DISABLED_FOR_MEMORY_TOOL();  // b/123500163
 | |
|   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);
 | |
| }
 | |
| 
 | |
| class JavaVmExtStackTraceTest : public JavaVmExtTest {
 | |
|  protected:
 | |
|   void SetUpRuntimeOptions(RuntimeOptions* options) override {
 | |
|     options->emplace_back("-XX:GlobalRefAllocStackTraceLimit=50000", nullptr);
 | |
|   }
 | |
| };
 | |
| 
 | |
| TEST_F(JavaVmExtStackTraceTest, TestEnableDisable) {
 | |
|   ASSERT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
 | |
| 
 | |
|   JNIEnv* env;
 | |
|   jint ok = vm_->AttachCurrentThread(&env, nullptr);
 | |
|   ASSERT_EQ(JNI_OK, ok);
 | |
| 
 | |
|   std::vector<jobject> global_refs_;
 | |
|   jobject local_ref = env->NewStringUTF("Hello");
 | |
|   for (size_t i = 0; i < 2000; ++i) {
 | |
|     global_refs_.push_back(env->NewGlobalRef(local_ref));
 | |
|   }
 | |
| 
 | |
|   EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
 | |
| 
 | |
|   for (jobject global_ref : global_refs_) {
 | |
|     env->DeleteGlobalRef(global_ref);
 | |
|   }
 | |
| 
 | |
|   EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
 | |
| 
 | |
|   global_refs_.clear();
 | |
|   for (size_t i = 0; i < 2000; ++i) {
 | |
|     global_refs_.push_back(env->NewGlobalRef(local_ref));
 | |
|   }
 | |
| 
 | |
|   EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
 | |
| 
 | |
|   for (jobject global_ref : global_refs_) {
 | |
|     env->DeleteGlobalRef(global_ref);
 | |
|   }
 | |
| 
 | |
|   EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
 | |
| 
 | |
|   ok = vm_->DetachCurrentThread();
 | |
|   EXPECT_EQ(JNI_OK, ok);
 | |
| }
 | |
| 
 | |
| }  // namespace art
 |