1 /* 2 * Copyright (C) 2013 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 <pthread.h> 18 19 #include <cstdio> 20 #include <iostream> 21 #include <vector> 22 23 #include <android-base/logging.h> 24 25 #include "art_method-inl.h" 26 #include "base/runtime_debug.h" 27 #include "jni.h" 28 29 namespace art { 30 31 static JavaVM* jvm = nullptr; 32 33 static jint Java_Main_intFastNativeMethod(JNIEnv*, jclass, jint a, jint b, jint c); 34 static jint Java_Main_intCriticalNativeMethod(jint a, jint b, jint c); 35 36 static JNINativeMethod sMainMethods[] = { 37 {"intFastNativeMethod", "(III)I", reinterpret_cast<void*>(Java_Main_intFastNativeMethod) }, 38 {"intCriticalNativeMethod", "(III)I", reinterpret_cast<void*>(Java_Main_intCriticalNativeMethod) }, 39 }; 40 41 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) { 42 CHECK(vm != nullptr); 43 CHECK(jvm == nullptr); 44 jvm = vm; 45 std::cout << "JNI_OnLoad called" << std::endl; 46 47 return JNI_VERSION_1_6; 48 } 49 50 extern "C" JNIEXPORT void JNI_OnUnload(JavaVM*, void*) { 51 // std::cout since LOG(INFO) adds extra stuff like pid. 52 std::cout << "JNI_OnUnload called" << std::endl; 53 // Clear jvm for CHECK in test 004-JniTest. 54 jvm = nullptr; 55 } 56 57 static void* AttachHelper(void* arg) { 58 CHECK(jvm != nullptr); 59 60 JNIEnv* env = nullptr; 61 JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, nullptr }; 62 int attach_result = jvm->AttachCurrentThread(&env, &args); 63 CHECK_EQ(attach_result, 0); 64 65 typedef void (*Fn)(JNIEnv*); 66 Fn fn = reinterpret_cast<Fn>(arg); 67 fn(env); 68 69 int detach_result = jvm->DetachCurrentThread(); 70 CHECK_EQ(detach_result, 0); 71 return nullptr; 72 } 73 74 static void PthreadHelper(void (*fn)(JNIEnv*)) { 75 pthread_t pthread; 76 int pthread_create_result = pthread_create(&pthread, nullptr, AttachHelper, 77 reinterpret_cast<void*>(fn)); 78 CHECK_EQ(pthread_create_result, 0); 79 int pthread_join_result = pthread_join(pthread, nullptr); 80 CHECK_EQ(pthread_join_result, 0); 81 } 82 83 static void testFindClassOnAttachedNativeThread(JNIEnv* env) { 84 jclass clazz = env->FindClass("Main"); 85 CHECK(clazz != nullptr); 86 CHECK(!env->ExceptionCheck()); 87 88 jobjectArray array = env->NewObjectArray(0, clazz, nullptr); 89 CHECK(array != nullptr); 90 CHECK(!env->ExceptionCheck()); 91 } 92 93 extern "C" JNIEXPORT jint JNICALL Java_Main_getFieldSubclass(JNIEnv* env, 94 jclass, 95 jobject f_obj, 96 jclass sub) { 97 jfieldID f = env->FromReflectedField(f_obj); 98 return env->GetStaticIntField(sub, f); 99 } 100 101 // http://b/10994325 102 extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*, jclass) { 103 PthreadHelper(&testFindClassOnAttachedNativeThread); 104 } 105 106 static void testFindFieldOnAttachedNativeThread(JNIEnv* env) { 107 jclass clazz = env->FindClass("Main"); 108 CHECK(clazz != nullptr); 109 CHECK(!env->ExceptionCheck()); 110 111 jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z"); 112 CHECK(field != nullptr); 113 CHECK(!env->ExceptionCheck()); 114 115 env->SetStaticBooleanField(clazz, field, JNI_TRUE); 116 } 117 118 extern "C" JNIEXPORT void JNICALL Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv*, 119 jclass) { 120 PthreadHelper(&testFindFieldOnAttachedNativeThread); 121 } 122 123 static void testReflectFieldGetFromAttachedNativeThread(JNIEnv* env) { 124 jclass clazz = env->FindClass("Main"); 125 CHECK(clazz != nullptr); 126 CHECK(!env->ExceptionCheck()); 127 128 jclass class_clazz = env->FindClass("java/lang/Class"); 129 CHECK(class_clazz != nullptr); 130 CHECK(!env->ExceptionCheck()); 131 132 jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField", 133 "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); 134 CHECK(getFieldMetodId != nullptr); 135 CHECK(!env->ExceptionCheck()); 136 137 jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField"); 138 CHECK(field_name != nullptr); 139 CHECK(!env->ExceptionCheck()); 140 141 jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name); 142 CHECK(field != nullptr); 143 CHECK(!env->ExceptionCheck()); 144 145 jclass field_clazz = env->FindClass("java/lang/reflect/Field"); 146 CHECK(field_clazz != nullptr); 147 CHECK(!env->ExceptionCheck()); 148 149 jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean", 150 "(Ljava/lang/Object;)Z"); 151 CHECK(getBooleanMetodId != nullptr); 152 CHECK(!env->ExceptionCheck()); 153 154 jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz); 155 CHECK(value == false); 156 CHECK(!env->ExceptionCheck()); 157 } 158 159 // http://b/15539150 160 extern "C" JNIEXPORT void JNICALL Java_Main_testReflectFieldGetFromAttachedNativeThreadNative( 161 JNIEnv*, jclass) { 162 PthreadHelper(&testReflectFieldGetFromAttachedNativeThread); 163 } 164 165 166 // http://b/11243757 167 extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, 168 jclass) { 169 jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass"); 170 CHECK(super_class != nullptr); 171 172 jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V"); 173 CHECK(execute != nullptr); 174 175 jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass"); 176 CHECK(sub_class != nullptr); 177 178 env->CallStaticVoidMethod(sub_class, execute); 179 } 180 181 extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) { 182 jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract"); 183 CHECK(abstract_class != nullptr); 184 jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z"); 185 CHECK(miranda_method != nullptr); 186 return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE); 187 } 188 189 // https://code.google.com/p/android/issues/detail?id=63055 190 extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) { 191 std::vector<uint8_t> buffer(1); 192 jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0); 193 CHECK(byte_buffer != nullptr); 194 CHECK(!env->ExceptionCheck()); 195 196 CHECK_EQ(env->GetDirectBufferAddress(byte_buffer), &buffer[0]); 197 CHECK_EQ(env->GetDirectBufferCapacity(byte_buffer), 0); 198 } 199 200 constexpr size_t kByteReturnSize = 7; 201 jbyte byte_returns[kByteReturnSize] = { 0, 1, 2, 127, -1, -2, -128 }; 202 203 extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv*, jclass, jbyte b1, jbyte b2, 204 jbyte b3, jbyte b4, jbyte b5, jbyte b6, 205 jbyte b7, jbyte b8, jbyte b9, jbyte b10) { 206 // We use b1 to drive the output. 207 CHECK_EQ(b2, 2); 208 CHECK_EQ(b3, -3); 209 CHECK_EQ(b4, 4); 210 CHECK_EQ(b5, -5); 211 CHECK_EQ(b6, 6); 212 CHECK_EQ(b7, -7); 213 CHECK_EQ(b8, 8); 214 CHECK_EQ(b9, -9); 215 CHECK_EQ(b10, 10); 216 217 CHECK_LE(0, b1); 218 CHECK_LT(b1, static_cast<jbyte>(kByteReturnSize)); 219 220 return byte_returns[b1]; 221 } 222 223 constexpr size_t kShortReturnSize = 9; 224 jshort short_returns[kShortReturnSize] = { 0, 1, 2, 127, 32767, -1, -2, -128, 225 static_cast<jshort>(0x8000) }; 226 // The weird static_cast is because short int is only guaranteed down to -32767, not Java's -32768. 227 228 extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv*, jclass, jshort s1, jshort s2, 229 jshort s3, jshort s4, jshort s5, jshort s6, 230 jshort s7, jshort s8, jshort s9, jshort s10) { 231 // We use s1 to drive the output. 232 CHECK_EQ(s2, 2); 233 CHECK_EQ(s3, -3); 234 CHECK_EQ(s4, 4); 235 CHECK_EQ(s5, -5); 236 CHECK_EQ(s6, 6); 237 CHECK_EQ(s7, -7); 238 CHECK_EQ(s8, 8); 239 CHECK_EQ(s9, -9); 240 CHECK_EQ(s10, 10); 241 242 CHECK_LE(0, s1); 243 CHECK_LT(s1, static_cast<jshort>(kShortReturnSize)); 244 245 return short_returns[s1]; 246 } 247 248 extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv*, jclass, jboolean b1, 249 jboolean b2, jboolean b3, jboolean b4, 250 jboolean b5, jboolean b6, jboolean b7, 251 jboolean b8, jboolean b9, jboolean b10) { 252 // We use b1 to drive the output. 253 CHECK_EQ(b2, JNI_TRUE); 254 CHECK_EQ(b3, JNI_FALSE); 255 CHECK_EQ(b4, JNI_TRUE); 256 CHECK_EQ(b5, JNI_FALSE); 257 CHECK_EQ(b6, JNI_TRUE); 258 CHECK_EQ(b7, JNI_FALSE); 259 CHECK_EQ(b8, JNI_TRUE); 260 CHECK_EQ(b9, JNI_FALSE); 261 CHECK_EQ(b10, JNI_TRUE); 262 263 CHECK(b1 == JNI_TRUE || b1 == JNI_FALSE); 264 return b1; 265 } 266 267 constexpr size_t kCharReturnSize = 8; 268 jchar char_returns[kCharReturnSize] = { 0, 1, 2, 127, 255, 256, 15000, 34000 }; 269 270 extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv*, jclass, jchar c1, jchar c2, 271 jchar c3, jchar c4, jchar c5, jchar c6, jchar c7, 272 jchar c8, jchar c9, jchar c10) { 273 // We use c1 to drive the output. 274 CHECK_EQ(c2, 'a'); 275 CHECK_EQ(c3, 'b'); 276 CHECK_EQ(c4, 'c'); 277 CHECK_EQ(c5, '0'); 278 CHECK_EQ(c6, '1'); 279 CHECK_EQ(c7, '2'); 280 CHECK_EQ(c8, 1234); 281 CHECK_EQ(c9, 2345); 282 CHECK_EQ(c10, 3456); 283 284 CHECK_LT(c1, static_cast<jchar>(kCharReturnSize)); 285 286 return char_returns[c1]; 287 } 288 289 extern "C" JNIEXPORT void JNICALL Java_Main_removeLocalObject(JNIEnv* env, jclass, jclass o) { 290 // Delete the arg to see if it crashes. 291 env->DeleteLocalRef(o); 292 } 293 294 extern "C" JNIEXPORT jboolean JNICALL Java_Main_nativeIsAssignableFrom(JNIEnv* env, jclass, 295 jclass from, jclass to) { 296 return env->IsAssignableFrom(from, to); 297 } 298 299 static void testShallowGetCallingClassLoader(JNIEnv* env) { 300 // Test direct call. 301 { 302 jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); 303 CHECK(vmstack_clazz != nullptr); 304 CHECK(!env->ExceptionCheck()); 305 306 jmethodID getCallingClassLoaderMethodId = env->GetStaticMethodID(vmstack_clazz, 307 "getCallingClassLoader", 308 "()Ljava/lang/ClassLoader;"); 309 CHECK(getCallingClassLoaderMethodId != nullptr); 310 CHECK(!env->ExceptionCheck()); 311 312 jobject class_loader = env->CallStaticObjectMethod(vmstack_clazz, 313 getCallingClassLoaderMethodId); 314 CHECK(class_loader == nullptr); 315 CHECK(!env->ExceptionCheck()); 316 } 317 318 // Test one-level call. Use System.loadLibrary(). 319 { 320 jclass system_clazz = env->FindClass("java/lang/System"); 321 CHECK(system_clazz != nullptr); 322 CHECK(!env->ExceptionCheck()); 323 324 jmethodID loadLibraryMethodId = env->GetStaticMethodID(system_clazz, "loadLibrary", 325 "(Ljava/lang/String;)V"); 326 CHECK(loadLibraryMethodId != nullptr); 327 CHECK(!env->ExceptionCheck()); 328 329 // Create a string object. 330 jobject library_string = env->NewStringUTF("non_existing_library"); 331 CHECK(library_string != nullptr); 332 CHECK(!env->ExceptionCheck()); 333 334 env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string); 335 CHECK(env->ExceptionCheck()); 336 337 // We expect UnsatisfiedLinkError. 338 jthrowable thrown = env->ExceptionOccurred(); 339 env->ExceptionClear(); 340 341 jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError"); 342 jclass thrown_class = env->GetObjectClass(thrown); 343 CHECK(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class)); 344 } 345 } 346 347 // http://b/16867274 348 extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoader(JNIEnv*, 349 jclass) { 350 PthreadHelper(&testShallowGetCallingClassLoader); 351 } 352 353 static void testShallowGetStackClass2(JNIEnv* env) { 354 jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); 355 CHECK(vmstack_clazz != nullptr); 356 CHECK(!env->ExceptionCheck()); 357 358 // Test direct call. 359 { 360 jmethodID getStackClass2MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass2", 361 "()Ljava/lang/Class;"); 362 CHECK(getStackClass2MethodId != nullptr); 363 CHECK(!env->ExceptionCheck()); 364 365 jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass2MethodId); 366 CHECK(caller_class == nullptr); 367 CHECK(!env->ExceptionCheck()); 368 } 369 370 // Test one-level call. Use VMStack.getStackClass1(). 371 { 372 jmethodID getStackClass1MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass1", 373 "()Ljava/lang/Class;"); 374 CHECK(getStackClass1MethodId != nullptr); 375 CHECK(!env->ExceptionCheck()); 376 377 jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass1MethodId); 378 CHECK(caller_class == nullptr); 379 CHECK(!env->ExceptionCheck()); 380 } 381 382 // For better testing we would need to compile against libcore and have a two-deep stack 383 // ourselves. 384 } 385 386 extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetStackClass2(JNIEnv*, jclass) { 387 PthreadHelper(&testShallowGetStackClass2); 388 } 389 390 class JniCallNonvirtualVoidMethodTest { 391 public: 392 explicit JniCallNonvirtualVoidMethodTest(JNIEnv* env) 393 : env_(env), 394 check_jni_ri_(true), 395 check_jni_android_(true), 396 super_(GetClass("JniCallNonvirtualTest")), 397 sub_(GetClass("JniCallNonvirtualTestSubclass")), 398 super_constructor_(GetMethodID(super_, true, "<init>")), 399 super_static_(GetMethodID(super_, false, "staticMethod")), 400 super_nonstatic_(GetMethodID(super_, true, "nonstaticMethod")), 401 sub_constructor_(GetMethodID(sub_, true, "<init>")), 402 sub_static_(GetMethodID(sub_, false, "staticMethod")), 403 sub_nonstatic_(GetMethodID(sub_, true, "nonstaticMethod")), 404 super_field_(GetFieldID(super_, "nonstaticMethodSuperCalled")), 405 sub_field_(GetFieldID(super_, "nonstaticMethodSubCalled")) {} 406 407 void Test() { 408 TestStaticCallNonvirtualMethod(); 409 TestNewObject(); 410 TestnonstaticCallNonvirtualMethod(); 411 } 412 413 JNIEnv* const env_; 414 415 bool const check_jni_ri_; 416 bool const check_jni_android_; 417 418 jclass const super_; 419 jclass const sub_; 420 421 jmethodID const super_constructor_; 422 jmethodID const super_static_; 423 jmethodID const super_nonstatic_; 424 jmethodID const sub_constructor_; 425 jmethodID const sub_static_; 426 jmethodID const sub_nonstatic_; 427 428 jfieldID const super_field_; 429 jfieldID const sub_field_; 430 431 private: 432 jclass GetClass(const char* class_name) { 433 jclass c = env_->FindClass(class_name); 434 if (env_->ExceptionCheck()) { 435 env_->ExceptionDescribe(); 436 env_->FatalError(__FUNCTION__); 437 } 438 CHECK(!env_->ExceptionCheck()); 439 CHECK(c != nullptr); 440 return c; 441 } 442 443 jmethodID GetMethodID(jclass c, bool nonstatic, const char* method_name) { 444 jmethodID m = ((nonstatic) ? 445 env_->GetMethodID(c, method_name, "()V") : 446 env_->GetStaticMethodID(c, method_name, "()V")); 447 if (env_->ExceptionCheck()) { 448 env_->ExceptionDescribe(); 449 env_->FatalError(__FUNCTION__); 450 } 451 CHECK(m != nullptr); 452 return m; 453 } 454 455 jobject CallConstructor(jclass c, jmethodID m) { 456 jobject o = env_->NewObject(c, m); 457 if (env_->ExceptionCheck()) { 458 env_->ExceptionDescribe(); 459 env_->FatalError(__FUNCTION__); 460 } 461 CHECK(o != nullptr); 462 return o; 463 } 464 465 void CallMethod(jobject o, jclass c, jmethodID m, bool nonstatic, const char* test_case) { 466 printf("RUNNING %s\n", test_case); 467 env_->CallNonvirtualVoidMethod(o, c, m); 468 bool exception_check = env_->ExceptionCheck(); 469 if (c == nullptr || !nonstatic) { 470 if (!exception_check) { 471 printf("FAILED %s due to missing exception\n", test_case); 472 env_->FatalError("Expected NullPointerException with null jclass"); 473 } 474 env_->ExceptionClear(); 475 } else if (exception_check) { 476 printf("FAILED %s due to pending exception\n", test_case); 477 env_->ExceptionDescribe(); 478 env_->FatalError(test_case); 479 } 480 printf("PASSED %s\n", test_case); 481 } 482 483 jfieldID GetFieldID(jclass c, const char* field_name) { 484 jfieldID m = env_->GetFieldID(c, field_name, "Z"); 485 if (env_->ExceptionCheck()) { 486 env_->ExceptionDescribe(); 487 env_->FatalError(__FUNCTION__); 488 } 489 CHECK(m != nullptr); 490 return m; 491 } 492 493 jboolean GetBooleanField(jobject o, jfieldID f) { 494 jboolean b = env_->GetBooleanField(o, f); 495 if (env_->ExceptionCheck()) { 496 env_->ExceptionDescribe(); 497 env_->FatalError(__FUNCTION__); 498 } 499 return b; 500 } 501 502 void TestStaticCallNonvirtualMethod() { 503 if (!check_jni_ri_&& !check_jni_android_) { 504 CallMethod(nullptr, nullptr, super_static_, false, "null object, null class, super static"); 505 } 506 if (!check_jni_android_) { 507 CallMethod(nullptr, super_, super_static_, false, "null object, super class, super static"); 508 } 509 if (!check_jni_android_) { 510 CallMethod(nullptr, sub_, super_static_, false, "null object, sub class, super static"); 511 } 512 513 if (!check_jni_ri_ && !check_jni_android_) { 514 CallMethod(nullptr, nullptr, sub_static_, false, "null object, null class, sub static"); 515 } 516 if (!check_jni_android_) { 517 CallMethod(nullptr, sub_, sub_static_, false, "null object, super class, sub static"); 518 } 519 if (!check_jni_android_) { 520 CallMethod(nullptr, super_, sub_static_, false, "null object, super class, sub static"); 521 } 522 } 523 524 void TestNewObject() { 525 jobject super_super = CallConstructor(super_, super_constructor_); 526 jobject super_sub = CallConstructor(super_, sub_constructor_); 527 jobject sub_super = CallConstructor(sub_, super_constructor_); 528 jobject sub_sub = CallConstructor(sub_, sub_constructor_); 529 530 CHECK(env_->IsInstanceOf(super_super, super_)); 531 CHECK(!env_->IsInstanceOf(super_super, sub_)); 532 533 // Note that even though we called (and ran) the subclass 534 // constructor, we are not the subclass. 535 CHECK(env_->IsInstanceOf(super_sub, super_)); 536 CHECK(!env_->IsInstanceOf(super_sub, sub_)); 537 538 // Note that even though we called the superclass constructor, we 539 // are still the subclass. 540 CHECK(env_->IsInstanceOf(sub_super, super_)); 541 CHECK(env_->IsInstanceOf(sub_super, sub_)); 542 543 CHECK(env_->IsInstanceOf(sub_sub, super_)); 544 CHECK(env_->IsInstanceOf(sub_sub, sub_)); 545 } 546 547 void TestnonstaticCallNonvirtualMethod(bool super_object, bool super_class, bool super_method, const char* test_case) { 548 if (check_jni_android_) { 549 if (super_object && !super_method) { 550 return; // We don't allow a call with sub class method on the super class instance. 551 } 552 if (super_class && !super_method) { 553 return; // We don't allow a call with the sub class method with the super class argument. 554 } 555 } 556 jobject o = ((super_object) ? 557 CallConstructor(super_, super_constructor_) : 558 CallConstructor(sub_, sub_constructor_)); 559 jclass c = (super_class) ? super_ : sub_; 560 jmethodID m = (super_method) ? super_nonstatic_ : sub_nonstatic_; 561 CallMethod(o, c, m, true, test_case); 562 jboolean super_field = GetBooleanField(o, super_field_); 563 jboolean sub_field = GetBooleanField(o, sub_field_); 564 CHECK_EQ(super_field, super_method); 565 CHECK_NE(sub_field, super_method); 566 } 567 568 void TestnonstaticCallNonvirtualMethod() { 569 TestnonstaticCallNonvirtualMethod(true, true, true, "super object, super class, super nonstatic"); 570 TestnonstaticCallNonvirtualMethod(true, false, true, "super object, sub class, super nonstatic"); 571 TestnonstaticCallNonvirtualMethod(true, false, false, "super object, sub class, sub nonstatic"); 572 TestnonstaticCallNonvirtualMethod(true, true, false, "super object, super class, sub nonstatic"); 573 574 TestnonstaticCallNonvirtualMethod(false, true, true, "sub object, super class, super nonstatic"); 575 TestnonstaticCallNonvirtualMethod(false, false, true, "sub object, sub class, super nonstatic"); 576 TestnonstaticCallNonvirtualMethod(false, false, false, "sub object, sub class, sub nonstatic"); 577 TestnonstaticCallNonvirtualMethod(false, true, false, "sub object, super class, sub nonstatic"); 578 } 579 }; 580 581 extern "C" void JNICALL Java_Main_testCallNonvirtual(JNIEnv* env, jclass) { 582 JniCallNonvirtualVoidMethodTest(env).Test(); 583 } 584 585 extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jclass) { 586 jclass c = env->FindClass("java/lang/String"); 587 CHECK(c != nullptr); 588 589 jmethodID mid1 = env->GetMethodID(c, "<init>", "()V"); 590 CHECK(mid1 != nullptr); 591 CHECK(!env->ExceptionCheck()); 592 jmethodID mid2 = env->GetMethodID(c, "<init>", "([B)V"); 593 CHECK(mid2 != nullptr); 594 CHECK(!env->ExceptionCheck()); 595 jmethodID mid3 = env->GetMethodID(c, "<init>", "([C)V"); 596 CHECK(mid3 != nullptr); 597 CHECK(!env->ExceptionCheck()); 598 jmethodID mid4 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V"); 599 CHECK(mid4 != nullptr); 600 CHECK(!env->ExceptionCheck()); 601 602 const char* test_array = "Test"; 603 int byte_array_length = strlen(test_array); 604 jbyteArray byte_array = env->NewByteArray(byte_array_length); 605 env->SetByteArrayRegion(byte_array, 0, byte_array_length, reinterpret_cast<const jbyte*>(test_array)); 606 607 // Test NewObject 608 jstring s = reinterpret_cast<jstring>(env->NewObject(c, mid2, byte_array)); 609 CHECK(s != nullptr); 610 CHECK_EQ(env->GetStringLength(s), byte_array_length); 611 CHECK_EQ(env->GetStringUTFLength(s), byte_array_length); 612 const char* chars = env->GetStringUTFChars(s, nullptr); 613 CHECK_EQ(strcmp(test_array, chars), 0); 614 env->ReleaseStringUTFChars(s, chars); 615 616 // Test AllocObject and Call(Nonvirtual)VoidMethod 617 jstring s1 = reinterpret_cast<jstring>(env->AllocObject(c)); 618 CHECK(s1 != nullptr); 619 jstring s2 = reinterpret_cast<jstring>(env->AllocObject(c)); 620 CHECK(s2 != nullptr); 621 jstring s3 = reinterpret_cast<jstring>(env->AllocObject(c)); 622 CHECK(s3 != nullptr); 623 jstring s4 = reinterpret_cast<jstring>(env->AllocObject(c)); 624 CHECK(s4 != nullptr); 625 626 jcharArray char_array = env->NewCharArray(5); 627 jstring string_arg = env->NewStringUTF("helloworld"); 628 629 // With Var Args 630 env->CallVoidMethod(s1, mid1); 631 env->CallNonvirtualVoidMethod(s2, c, mid2, byte_array); 632 633 // With JValues 634 jvalue args3[1]; 635 args3[0].l = char_array; 636 jvalue args4[1]; 637 args4[0].l = string_arg; 638 env->CallVoidMethodA(s3, mid3, args3); 639 env->CallNonvirtualVoidMethodA(s4, c, mid4, args4); 640 641 // Test with global and weak global references 642 jstring s5 = reinterpret_cast<jstring>(env->AllocObject(c)); 643 CHECK(s5 != nullptr); 644 s5 = reinterpret_cast<jstring>(env->NewGlobalRef(s5)); 645 jstring s6 = reinterpret_cast<jstring>(env->AllocObject(c)); 646 CHECK(s6 != nullptr); 647 s6 = reinterpret_cast<jstring>(env->NewWeakGlobalRef(s6)); 648 649 env->CallVoidMethod(s5, mid1); 650 env->CallNonvirtualVoidMethod(s6, c, mid2, byte_array); 651 CHECK_EQ(env->GetStringLength(s5), 0); 652 CHECK_EQ(env->GetStringLength(s6), byte_array_length); 653 const char* chars6 = env->GetStringUTFChars(s6, nullptr); 654 CHECK_EQ(strcmp(test_array, chars6), 0); 655 env->ReleaseStringUTFChars(s6, chars6); 656 } 657 658 extern "C" JNIEXPORT jlong JNICALL Java_Main_testGetMethodID(JNIEnv* env, jclass, jclass c) { 659 return reinterpret_cast<jlong>(env->GetMethodID(c, "a", "()V")); 660 } 661 662 extern "C" JNIEXPORT void JNICALL Java_Main_enterJniCriticalSection(JNIEnv* env, jclass, 663 jint arraySize, 664 jbyteArray array0, 665 jbyteArray array1) { 666 for (int i = 0; i < 50000; ++i) { 667 char* data0 = reinterpret_cast<char*>(env->GetPrimitiveArrayCritical(array0, nullptr)); 668 char* data1 = reinterpret_cast<char*>(env->GetPrimitiveArrayCritical(array1, nullptr)); 669 bool up = i % 2 == 0; 670 for (int j = 0; j < arraySize; ++j) { 671 if (up) { 672 data1[j] = data0[j] + 1; 673 } else { 674 data0[j] = data1[j] + 1; 675 } 676 } 677 env->ReleasePrimitiveArrayCritical(array1, data1, 0); 678 env->ReleasePrimitiveArrayCritical(array0, data0, 0); 679 } 680 } 681 682 class JniCallDefaultMethodsTest { 683 public: 684 explicit JniCallDefaultMethodsTest(JNIEnv* env) 685 : env_(env), concrete_class_(env_->FindClass("ConcreteClass")) { 686 CHECK(!env_->ExceptionCheck()); 687 CHECK(concrete_class_ != nullptr); 688 } 689 690 void Test() { 691 TestCalls("ConcreteClass", { "JniCallNonOverridenDefaultMethod", 692 "JniCallOverridenDefaultMethod", 693 "JniCallOverridenDefaultMethodWithSuper", 694 "JniCallOverridenAbstractMethod", 695 "JniCallConflictDefaultMethod", 696 "JniCallSoftConflictMethod" }); 697 TestCalls("DefaultInterface", { "JniCallNonOverridenDefaultMethod", 698 "JniCallOverridenDefaultMethod", 699 "JniCallOverridenAbstractMethod", 700 "JniCallConflictDefaultMethod", 701 "JniCallSoftConflictMethod" }); 702 TestCalls("AbstractInterface", { "JniCallSoftConflictMethod" }); 703 TestCalls("ConflictInterface", { "JniCallConflictDefaultMethod" }); 704 } 705 706 private: 707 void TestCalls(const char* declaring_class, std::vector<const char*> methods) { 708 jmethodID new_method = env_->GetMethodID(concrete_class_, "<init>", "()V"); 709 jobject obj = env_->NewObject(concrete_class_, new_method); 710 CHECK(!env_->ExceptionCheck()); 711 CHECK(obj != nullptr); 712 jclass decl_class = env_->FindClass(declaring_class); 713 CHECK(!env_->ExceptionCheck()); 714 CHECK(decl_class != nullptr); 715 for (const char* method : methods) { 716 jmethodID method_id = env_->GetMethodID(decl_class, method, "()V"); 717 CHECK(!env_->ExceptionCheck()); 718 printf("Calling method %s->%s on object of type ConcreteClass\n", declaring_class, method); 719 env_->CallVoidMethod(obj, method_id); 720 if (env_->ExceptionCheck()) { 721 jthrowable thrown = env_->ExceptionOccurred(); 722 env_->ExceptionClear(); 723 jmethodID to_string = env_->GetMethodID( 724 env_->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;"); 725 jstring exception_string = (jstring) env_->CallObjectMethod(thrown, to_string); 726 CHECK(!env_->ExceptionCheck()); 727 const char* exception_string_utf8 = env_->GetStringUTFChars(exception_string, nullptr); 728 CHECK(!env_->ExceptionCheck()); 729 CHECK(exception_string_utf8 != nullptr); 730 printf("EXCEPTION OCCURED: %s\n", exception_string_utf8); 731 env_->ReleaseStringUTFChars(exception_string, exception_string_utf8); 732 } 733 } 734 } 735 736 JNIEnv* env_; 737 jclass concrete_class_; 738 }; 739 740 extern "C" JNIEXPORT void JNICALL Java_Main_testCallDefaultMethods(JNIEnv* env) { 741 JniCallDefaultMethodsTest(env).Test(); 742 } 743 744 static void InvokeSpecificMethod(JNIEnv* env, jobject obj, const char* method) { 745 jclass lambda_class = env->FindClass("LambdaInterface"); 746 CHECK(!env->ExceptionCheck()); 747 CHECK(lambda_class != nullptr); 748 jmethodID method_id = env->GetMethodID(lambda_class, method, "()V"); 749 CHECK(!env->ExceptionCheck()); 750 env->CallVoidMethod(obj, method_id); 751 CHECK(!env->ExceptionCheck()); 752 } 753 754 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod( 755 JNIEnv* e, jclass, jobject l) { 756 InvokeSpecificMethod(e, l, "sayHiTwice"); 757 } 758 759 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaMethod(JNIEnv* e, jclass, jobject l) { 760 InvokeSpecificMethod(e, l, "sayHi"); 761 } 762 763 // Register on-demand because many tests share this JNI library and 764 // we can't unconditionally register them. 765 extern "C" JNIEXPORT jboolean JNICALL Java_Main_registerNativesJniTest(JNIEnv* e, jclass kls) { 766 const size_t numMethods = sizeof(sMainMethods)/sizeof(JNINativeMethod); 767 768 if (e->RegisterNatives(kls, sMainMethods, numMethods) < 0) { 769 std::cerr << "RegisterNatives failed for 'Main'" << std::endl; 770 return JNI_FALSE; 771 } 772 773 return JNI_TRUE; 774 } 775 776 // Annotated with @FastNative in Java code. Doesn't need to be explicitly registered with "!". 777 // NOTE: Has to be registered explicitly to avoid mutator lock check failures. 778 static jint Java_Main_intFastNativeMethod(JNIEnv*, jclass, jint a, jint b, jint c) { 779 return a + b + c; 780 } 781 782 // Annotated with @CriticalNative in Java code. Doesn't need to be explicitly registered with "!". 783 // NOTE: Has to be registered explicitly to avoid mutator lock check failures. 784 static jint Java_Main_intCriticalNativeMethod(jint a, jint b, jint c) { 785 // Note that unlike a "Fast Native" method this excludes JNIEnv and the jclass parameters. 786 return a + b + c; 787 } 788 789 extern "C" JNIEXPORT jobject JNICALL Java_Main_lookupClinit(JNIEnv* env, jclass, jclass kls) { 790 jmethodID clinit_id = env->GetStaticMethodID(kls, "<clinit>", "()V"); 791 792 if (clinit_id != nullptr) { 793 jobject obj = env->ToReflectedMethod(kls, clinit_id, /*isStatic*/ true); 794 CHECK(obj != nullptr); 795 return obj; 796 } else { 797 return nullptr; 798 } 799 } 800 801 extern "C" JNIEXPORT jboolean JNICALL Java_Main_isSlowDebug(JNIEnv*, jclass) { 802 // Return whether slow-debug is on. Only relevant for debug builds. 803 if (kIsDebugBuild) { 804 // Register a dummy flag and get the default value it should be initialized with. 805 static bool dummy_flag = false; 806 dummy_flag = RegisterRuntimeDebugFlag(&dummy_flag); 807 808 return dummy_flag ? JNI_TRUE : JNI_FALSE; 809 } 810 // To pass the Java-side test, just so "on" for release builds. 811 return JNI_TRUE; 812 } 813 814 } // namespace art 815 816