• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "jni/jni_internal.h"
18 
19 #include <pthread.h>
20 
21 #include "common_runtime_test.h"
22 #include "gc/heap.h"
23 #include "java_vm_ext.h"
24 #include "runtime.h"
25 
26 namespace art {
27 
28 class JavaVmExtTest : public CommonRuntimeTest {
29  protected:
JavaVmExtTest()30   JavaVmExtTest() {
31     this->use_boot_image_ = true;  // Make the Runtime creation cheaper.
32   }
33 
SetUp()34   void SetUp() override {
35     CommonRuntimeTest::SetUp();
36 
37     vm_ = Runtime::Current()->GetJavaVM();
38   }
39 
40 
TearDown()41   void TearDown() override {
42     CommonRuntimeTest::TearDown();
43   }
44 
45   JavaVMExt* vm_;
46 };
47 
TEST_F(JavaVmExtTest,JNI_GetDefaultJavaVMInitArgs)48 TEST_F(JavaVmExtTest, JNI_GetDefaultJavaVMInitArgs) {
49   jint err = JNI_GetDefaultJavaVMInitArgs(nullptr);
50   EXPECT_EQ(JNI_ERR, err);
51 }
52 
TEST_F(JavaVmExtTest,JNI_GetCreatedJavaVMs)53 TEST_F(JavaVmExtTest, JNI_GetCreatedJavaVMs) {
54   JavaVM* vms_buf[1];
55   jsize num_vms;
56   jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
57   EXPECT_EQ(JNI_OK, ok);
58   EXPECT_EQ(1, num_vms);
59   EXPECT_EQ(vms_buf[0], vm_);
60 }
61 
62 static bool gSmallStack = false;
63 static bool gAsDaemon = false;
64 
attach_current_thread_callback(void * arg ATTRIBUTE_UNUSED)65 static void* attach_current_thread_callback(void* arg ATTRIBUTE_UNUSED) {
66   JavaVM* vms_buf[1];
67   jsize num_vms;
68   JNIEnv* env;
69   jint ok = JNI_GetCreatedJavaVMs(vms_buf, arraysize(vms_buf), &num_vms);
70   EXPECT_EQ(JNI_OK, ok);
71   if (ok == JNI_OK) {
72     if (!gAsDaemon) {
73       ok = vms_buf[0]->AttachCurrentThread(&env, nullptr);
74     } else {
75       ok = vms_buf[0]->AttachCurrentThreadAsDaemon(&env, nullptr);
76     }
77     // TODO: Find a way to test with exact SMALL_STACK value, for which we would bail. The pthreads
78     //       spec says that the stack size argument is a lower bound, and bionic currently gives us
79     //       a chunk more on arm64.
80     if (!gSmallStack) {
81       EXPECT_EQ(JNI_OK, ok);
82     }
83     if (ok == JNI_OK) {
84       ok = vms_buf[0]->DetachCurrentThread();
85       EXPECT_EQ(JNI_OK, ok);
86     }
87   }
88   return nullptr;
89 }
90 
TEST_F(JavaVmExtTest,AttachCurrentThread)91 TEST_F(JavaVmExtTest, AttachCurrentThread) {
92   pthread_t pthread;
93   const char* reason = __PRETTY_FUNCTION__;
94   gSmallStack = false;
95   gAsDaemon = false;
96   CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
97       nullptr), reason);
98   void* ret_val;
99   CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
100   EXPECT_EQ(ret_val, nullptr);
101 }
102 
TEST_F(JavaVmExtTest,AttachCurrentThreadAsDaemon)103 TEST_F(JavaVmExtTest, AttachCurrentThreadAsDaemon) {
104   pthread_t pthread;
105   const char* reason = __PRETTY_FUNCTION__;
106   gSmallStack = false;
107   gAsDaemon = true;
108   CHECK_PTHREAD_CALL(pthread_create, (&pthread, nullptr, attach_current_thread_callback,
109       nullptr), reason);
110   void* ret_val;
111   CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
112   EXPECT_EQ(ret_val, nullptr);
113 }
114 
TEST_F(JavaVmExtTest,AttachCurrentThread_SmallStack)115 TEST_F(JavaVmExtTest, AttachCurrentThread_SmallStack) {
116   TEST_DISABLED_FOR_MEMORY_TOOL();  // b/123500163
117   pthread_t pthread;
118   pthread_attr_t attr;
119   const char* reason = __PRETTY_FUNCTION__;
120   gSmallStack = true;
121   gAsDaemon = false;
122   CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
123   CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, PTHREAD_STACK_MIN), reason);
124   CHECK_PTHREAD_CALL(pthread_create, (&pthread, &attr, attach_current_thread_callback,
125       nullptr), reason);
126   CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
127   void* ret_val;
128   CHECK_PTHREAD_CALL(pthread_join, (pthread, &ret_val), reason);
129   EXPECT_EQ(ret_val, nullptr);
130 }
131 
TEST_F(JavaVmExtTest,DetachCurrentThread)132 TEST_F(JavaVmExtTest, DetachCurrentThread) {
133   JNIEnv* env;
134   jint ok = vm_->AttachCurrentThread(&env, nullptr);
135   ASSERT_EQ(JNI_OK, ok);
136   ok = vm_->DetachCurrentThread();
137   EXPECT_EQ(JNI_OK, ok);
138 
139   jint err = vm_->DetachCurrentThread();
140   EXPECT_EQ(JNI_ERR, err);
141 }
142 
143 class JavaVmExtStackTraceTest : public JavaVmExtTest {
144  protected:
SetUpRuntimeOptions(RuntimeOptions * options)145   void SetUpRuntimeOptions(RuntimeOptions* options) override {
146     options->emplace_back("-XX:GlobalRefAllocStackTraceLimit=50000", nullptr);
147   }
148 };
149 
TEST_F(JavaVmExtStackTraceTest,TestEnableDisable)150 TEST_F(JavaVmExtStackTraceTest, TestEnableDisable) {
151   ASSERT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
152 
153   JNIEnv* env;
154   jint ok = vm_->AttachCurrentThread(&env, nullptr);
155   ASSERT_EQ(JNI_OK, ok);
156 
157   std::vector<jobject> global_refs_;
158   jobject local_ref = env->NewStringUTF("Hello");
159   for (size_t i = 0; i < 2000; ++i) {
160     global_refs_.push_back(env->NewGlobalRef(local_ref));
161   }
162 
163   EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
164 
165   for (jobject global_ref : global_refs_) {
166     env->DeleteGlobalRef(global_ref);
167   }
168 
169   EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
170 
171   global_refs_.clear();
172   for (size_t i = 0; i < 2000; ++i) {
173     global_refs_.push_back(env->NewGlobalRef(local_ref));
174   }
175 
176   EXPECT_TRUE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
177 
178   for (jobject global_ref : global_refs_) {
179     env->DeleteGlobalRef(global_ref);
180   }
181 
182   EXPECT_FALSE(Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
183 
184   ok = vm_->DetachCurrentThread();
185   EXPECT_EQ(JNI_OK, ok);
186 }
187 
188 }  // namespace art
189