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