1 /* 2 * Copyright (C) 2008 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 * Basic reflection calls and utility functions. 18 */ 19 #include "Dalvik.h" 20 21 #include <stdlib.h> 22 23 /* 24 * Cache some classes. 25 */ 26 bool dvmReflectStartup(void) 27 { 28 gDvm.classJavaLangReflectAccessibleObject = 29 dvmFindSystemClassNoInit("Ljava/lang/reflect/AccessibleObject;"); 30 gDvm.classJavaLangReflectConstructor = 31 dvmFindSystemClassNoInit("Ljava/lang/reflect/Constructor;"); 32 gDvm.classJavaLangReflectConstructorArray = 33 dvmFindArrayClass("[Ljava/lang/reflect/Constructor;", NULL); 34 gDvm.classJavaLangReflectField = 35 dvmFindSystemClassNoInit("Ljava/lang/reflect/Field;"); 36 gDvm.classJavaLangReflectFieldArray = 37 dvmFindArrayClass("[Ljava/lang/reflect/Field;", NULL); 38 gDvm.classJavaLangReflectMethod = 39 dvmFindSystemClassNoInit("Ljava/lang/reflect/Method;"); 40 gDvm.classJavaLangReflectMethodArray = 41 dvmFindArrayClass("[Ljava/lang/reflect/Method;", NULL); 42 gDvm.classJavaLangReflectProxy = 43 dvmFindSystemClassNoInit("Ljava/lang/reflect/Proxy;"); 44 if (gDvm.classJavaLangReflectAccessibleObject == NULL || 45 gDvm.classJavaLangReflectConstructor == NULL || 46 gDvm.classJavaLangReflectConstructorArray == NULL || 47 gDvm.classJavaLangReflectField == NULL || 48 gDvm.classJavaLangReflectFieldArray == NULL || 49 gDvm.classJavaLangReflectMethod == NULL || 50 gDvm.classJavaLangReflectMethodArray == NULL || 51 gDvm.classJavaLangReflectProxy == NULL) 52 { 53 LOGE("Could not find one or more reflection classes\n"); 54 return false; 55 } 56 57 gDvm.methJavaLangReflectConstructor_init = 58 dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectConstructor, "<init>", 59 "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;I)V"); 60 gDvm.methJavaLangReflectField_init = 61 dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectField, "<init>", 62 "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V"); 63 gDvm.methJavaLangReflectMethod_init = 64 dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectMethod, "<init>", 65 "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V"); 66 if (gDvm.methJavaLangReflectConstructor_init == NULL || 67 gDvm.methJavaLangReflectField_init == NULL || 68 gDvm.methJavaLangReflectMethod_init == NULL) 69 { 70 LOGE("Could not find reflection constructors\n"); 71 return false; 72 } 73 74 gDvm.classJavaLangClassArray = 75 dvmFindArrayClass("[Ljava/lang/Class;", NULL); 76 gDvm.classJavaLangObjectArray = 77 dvmFindArrayClass("[Ljava/lang/Object;", NULL); 78 if (gDvm.classJavaLangClassArray == NULL || 79 gDvm.classJavaLangObjectArray == NULL) 80 { 81 LOGE("Could not find class-array or object-array class\n"); 82 return false; 83 } 84 85 gDvm.offJavaLangReflectAccessibleObject_flag = 86 dvmFindFieldOffset(gDvm.classJavaLangReflectAccessibleObject, "flag", 87 "Z"); 88 89 gDvm.offJavaLangReflectConstructor_slot = 90 dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor, "slot", "I"); 91 gDvm.offJavaLangReflectConstructor_declClass = 92 dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor, 93 "declaringClass", "Ljava/lang/Class;"); 94 95 gDvm.offJavaLangReflectField_slot = 96 dvmFindFieldOffset(gDvm.classJavaLangReflectField, "slot", "I"); 97 gDvm.offJavaLangReflectField_declClass = 98 dvmFindFieldOffset(gDvm.classJavaLangReflectField, 99 "declaringClass", "Ljava/lang/Class;"); 100 101 gDvm.offJavaLangReflectMethod_slot = 102 dvmFindFieldOffset(gDvm.classJavaLangReflectMethod, "slot", "I"); 103 gDvm.offJavaLangReflectMethod_declClass = 104 dvmFindFieldOffset(gDvm.classJavaLangReflectMethod, 105 "declaringClass", "Ljava/lang/Class;"); 106 107 if (gDvm.offJavaLangReflectAccessibleObject_flag < 0 || 108 gDvm.offJavaLangReflectConstructor_slot < 0 || 109 gDvm.offJavaLangReflectConstructor_declClass < 0 || 110 gDvm.offJavaLangReflectField_slot < 0 || 111 gDvm.offJavaLangReflectField_declClass < 0 || 112 gDvm.offJavaLangReflectMethod_slot < 0 || 113 gDvm.offJavaLangReflectMethod_declClass < 0) 114 { 115 LOGE("Could not find reflection fields\n"); 116 return false; 117 } 118 119 if (!dvmReflectProxyStartup()) 120 return false; 121 if (!dvmReflectAnnotationStartup()) 122 return false; 123 124 return true; 125 } 126 127 /* 128 * Clean up. 129 */ 130 void dvmReflectShutdown(void) 131 { 132 // nothing to do 133 } 134 135 /* 136 * For some of the reflection stuff we need to un-box primitives, e.g. 137 * convert a java/lang/Integer to int or even a float. We assume that 138 * the first instance field holds the value. 139 * 140 * To verify this, we either need to ensure that the class has only one 141 * instance field, or we need to look up the field by name and verify 142 * that it comes first. The former is simpler, and should work. 143 */ 144 bool dvmValidateBoxClasses() 145 { 146 static const char* classes[] = { 147 "Ljava/lang/Boolean;", 148 "Ljava/lang/Character;", 149 "Ljava/lang/Float;", 150 "Ljava/lang/Double;", 151 "Ljava/lang/Byte;", 152 "Ljava/lang/Short;", 153 "Ljava/lang/Integer;", 154 "Ljava/lang/Long;", 155 NULL 156 }; 157 const char** ccp; 158 159 for (ccp = classes; *ccp != NULL; ccp++) { 160 ClassObject* clazz; 161 162 clazz = dvmFindClassNoInit(*ccp, NULL); 163 if (clazz == NULL) { 164 LOGE("Couldn't find '%s'\n", *ccp); 165 return false; 166 } 167 168 if (clazz->ifieldCount != 1) { 169 LOGE("Found %d instance fields in '%s'\n", 170 clazz->ifieldCount, *ccp); 171 return false; 172 } 173 } 174 175 return true; 176 } 177 178 179 /* 180 * Find the named class object. We have to trim "*pSignature" down to just 181 * the first token, do the lookup, and then restore anything important 182 * that we've stomped on. 183 * 184 * "pSig" will be advanced to the start of the next token. 185 */ 186 static ClassObject* convertSignaturePartToClass(char** pSignature, 187 const ClassObject* defClass) 188 { 189 ClassObject* clazz = NULL; 190 char* signature = *pSignature; 191 192 if (*signature == '[') { 193 /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */ 194 char savedChar; 195 196 while (*++signature == '[') 197 ; 198 if (*signature == 'L') { 199 while (*++signature != ';') 200 ; 201 } 202 203 /* advance past ';', and stomp on whatever comes next */ 204 savedChar = *++signature; 205 *signature = '\0'; 206 clazz = dvmFindArrayClass(*pSignature, defClass->classLoader); 207 *signature = savedChar; 208 } else if (*signature == 'L') { 209 /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */ 210 char savedChar; 211 while (*++signature != ';') 212 ; 213 savedChar = *++signature; 214 *signature = '\0'; 215 clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader); 216 *signature = savedChar; 217 } else { 218 clazz = dvmFindPrimitiveClass(*signature++); 219 } 220 221 if (clazz == NULL) { 222 LOGW("Unable to match class for part: '%s'\n", *pSignature); 223 dvmClearException(dvmThreadSelf()); 224 dvmThrowException("Ljava/lang/NoSuchMethodException;", NULL); 225 } 226 *pSignature = signature; 227 return clazz; 228 } 229 230 /* 231 * Convert the method signature to an array of classes. 232 * 233 * The tokenization process may mangle "*pSignature". On return, it will 234 * be pointing at the closing ')'. 235 * 236 * "defClass" is the method's class, which is needed to make class loaders 237 * happy. 238 */ 239 static ArrayObject* convertSignatureToClassArray(char** pSignature, 240 ClassObject* defClass) 241 { 242 ArrayObject* classArray; 243 char* signature = *pSignature; 244 char* cp; 245 int i, count; 246 247 assert(*signature == '('); 248 signature++; 249 250 /* count up the number of parameters */ 251 count = 0; 252 cp = signature; 253 while (*cp != ')') { 254 count++; 255 256 if (*cp == '[') { 257 while (*++cp == '[') 258 ; 259 } 260 if (*cp == 'L') { 261 while (*++cp != ';') 262 ; 263 } 264 cp++; 265 } 266 LOGVV("REFLECT found %d parameters in '%s'\n", count, *pSignature); 267 268 /* create an array to hold them */ 269 classArray = dvmAllocArray(gDvm.classJavaLangClassArray, count, 270 kObjectArrayRefWidth, ALLOC_DEFAULT); 271 if (classArray == NULL) 272 return NULL; 273 274 /* fill it in */ 275 cp = signature; 276 for (i = 0; i < count; i++) { 277 ClassObject* clazz; 278 279 clazz = convertSignaturePartToClass(&cp, defClass); 280 if (clazz == NULL) { 281 assert(dvmCheckException(dvmThreadSelf())); 282 return NULL; 283 } 284 LOGVV("REFLECT %d: '%s'\n", i, clazz->descriptor); 285 dvmSetObjectArrayElement(classArray, i, (Object *)clazz); 286 } 287 288 *pSignature = cp; 289 290 /* caller must call dvmReleaseTrackedAlloc */ 291 return classArray; 292 } 293 294 295 /* 296 * Convert a field pointer to a slot number. 297 * 298 * We use positive values starting from 0 for instance fields, negative 299 * values starting from -1 for static fields. 300 */ 301 static int fieldToSlot(const Field* field, const ClassObject* clazz) 302 { 303 int slot; 304 305 if (dvmIsStaticField(field)) { 306 slot = (StaticField*)field - &clazz->sfields[0]; 307 assert(slot >= 0 && slot < clazz->sfieldCount); 308 slot = -(slot+1); 309 } else { 310 slot = (InstField*)field - clazz->ifields; 311 assert(slot >= 0 && slot < clazz->ifieldCount); 312 } 313 314 return slot; 315 } 316 317 /* 318 * Convert a slot number to a field pointer. 319 */ 320 Field* dvmSlotToField(ClassObject* clazz, int slot) 321 { 322 if (slot < 0) { 323 slot = -(slot+1); 324 assert(slot < clazz->sfieldCount); 325 return (Field*) &clazz->sfields[slot]; 326 } else { 327 assert(slot < clazz->ifieldCount); 328 return (Field*) &clazz->ifields[slot]; 329 } 330 } 331 332 /* 333 * Create a new java.lang.reflect.Field object from "field". 334 * 335 * The Field spec doesn't specify the constructor. We're going to use the 336 * one from our existing class libs: 337 * 338 * private Field(Class declaringClass, Class type, String name, int slot) 339 */ 340 static Object* createFieldObject(Field* field, const ClassObject* clazz) 341 { 342 Object* result = NULL; 343 Object* fieldObj = NULL; 344 StringObject* nameObj = NULL; 345 ClassObject* type; 346 char* mangle; 347 char* cp; 348 int slot; 349 350 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField)); 351 352 fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT); 353 if (fieldObj == NULL) 354 goto bail; 355 356 cp = mangle = strdup(field->signature); 357 type = convertSignaturePartToClass(&cp, clazz); 358 free(mangle); 359 if (type == NULL) 360 goto bail; 361 362 nameObj = dvmCreateStringFromCstr(field->name); 363 if (nameObj == NULL) 364 goto bail; 365 366 slot = fieldToSlot(field, clazz); 367 368 JValue unused; 369 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init, 370 fieldObj, &unused, clazz, type, nameObj, slot); 371 if (dvmCheckException(dvmThreadSelf())) { 372 LOGD("Field class init threw exception\n"); 373 goto bail; 374 } 375 376 result = fieldObj; 377 378 bail: 379 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 380 if (result == NULL) 381 dvmReleaseTrackedAlloc((Object*) fieldObj, NULL); 382 /* caller must dvmReleaseTrackedAlloc(result) */ 383 return result; 384 } 385 386 /* 387 * 388 * Get an array with all fields declared by a class. 389 * 390 * This includes both static and instance fields. 391 */ 392 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly) 393 { 394 ArrayObject* fieldArray = NULL; 395 int i, count; 396 397 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 398 dvmInitClass(gDvm.classJavaLangReflectField); 399 400 /* count #of fields */ 401 if (!publicOnly) 402 count = clazz->sfieldCount + clazz->ifieldCount; 403 else { 404 count = 0; 405 for (i = 0; i < clazz->sfieldCount; i++) { 406 if ((clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) 407 count++; 408 } 409 for (i = 0; i < clazz->ifieldCount; i++) { 410 if ((clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) 411 count++; 412 } 413 } 414 415 /* create the Field[] array */ 416 fieldArray = dvmAllocArray(gDvm.classJavaLangReflectFieldArray, count, 417 kObjectArrayRefWidth, ALLOC_DEFAULT); 418 if (fieldArray == NULL) 419 return NULL; 420 421 /* populate */ 422 size_t fieldCount = 0; 423 for (i = 0; i < clazz->sfieldCount; i++) { 424 if (!publicOnly || 425 (clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) 426 { 427 Object* field = createFieldObject(&clazz->sfields[i].field, clazz); 428 if (field == NULL) { 429 goto fail; 430 } 431 dvmSetObjectArrayElement(fieldArray, fieldCount, field); 432 dvmReleaseTrackedAlloc(field, NULL); 433 ++fieldCount; 434 } 435 } 436 for (i = 0; i < clazz->ifieldCount; i++) { 437 if (!publicOnly || 438 (clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) 439 { 440 Object* field = createFieldObject(&clazz->ifields[i].field, clazz); 441 if (field == NULL) { 442 goto fail; 443 } 444 dvmSetObjectArrayElement(fieldArray, fieldCount, field); 445 dvmReleaseTrackedAlloc(field, NULL); 446 ++fieldCount; 447 } 448 } 449 450 assert(fieldCount == fieldArray->length); 451 452 /* caller must call dvmReleaseTrackedAlloc */ 453 return fieldArray; 454 455 fail: 456 dvmReleaseTrackedAlloc((Object*) fieldArray, NULL); 457 return NULL; 458 } 459 460 461 /* 462 * Convert a method pointer to a slot number. 463 * 464 * We use positive values starting from 0 for virtual methods, negative 465 * values starting from -1 for static methods. 466 */ 467 static int methodToSlot(const Method* meth) 468 { 469 ClassObject* clazz = meth->clazz; 470 int slot; 471 472 if (dvmIsDirectMethod(meth)) { 473 slot = meth - clazz->directMethods; 474 assert(slot >= 0 && slot < clazz->directMethodCount); 475 slot = -(slot+1); 476 } else { 477 slot = meth - clazz->virtualMethods; 478 assert(slot >= 0 && slot < clazz->virtualMethodCount); 479 } 480 481 return slot; 482 } 483 484 /* 485 * Convert a slot number to a method pointer. 486 */ 487 Method* dvmSlotToMethod(ClassObject* clazz, int slot) 488 { 489 if (slot < 0) { 490 slot = -(slot+1); 491 assert(slot < clazz->directMethodCount); 492 return &clazz->directMethods[slot]; 493 } else { 494 assert(slot < clazz->virtualMethodCount); 495 return &clazz->virtualMethods[slot]; 496 } 497 } 498 499 /* 500 * Create a new java/lang/reflect/Constructor object, using the contents of 501 * "meth" to construct it. 502 * 503 * The spec doesn't specify the constructor. We're going to use the 504 * one from our existing class libs: 505 * 506 * private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes, 507 * int slot) 508 */ 509 static Object* createConstructorObject(Method* meth) 510 { 511 Object* result = NULL; 512 ArrayObject* params = NULL; 513 ArrayObject* exceptions = NULL; 514 Object* consObj; 515 DexStringCache mangle; 516 char* cp; 517 int slot; 518 519 dexStringCacheInit(&mangle); 520 521 /* parent should guarantee init so we don't have to check on every call */ 522 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)); 523 524 consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor, 525 ALLOC_DEFAULT); 526 if (consObj == NULL) 527 goto bail; 528 529 /* 530 * Convert the signature string into an array of classes representing 531 * the arguments. 532 */ 533 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); 534 params = convertSignatureToClassArray(&cp, meth->clazz); 535 if (params == NULL) 536 goto bail; 537 assert(*cp == ')'); 538 assert(*(cp+1) == 'V'); 539 540 /* 541 * Create an array with one entry for every exception that the class 542 * is declared to throw. 543 */ 544 exceptions = dvmGetMethodThrows(meth); 545 if (dvmCheckException(dvmThreadSelf())) 546 goto bail; 547 548 slot = methodToSlot(meth); 549 550 JValue unused; 551 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init, 552 consObj, &unused, meth->clazz, params, exceptions, slot); 553 if (dvmCheckException(dvmThreadSelf())) { 554 LOGD("Constructor class init threw exception\n"); 555 goto bail; 556 } 557 558 result = consObj; 559 560 bail: 561 dexStringCacheRelease(&mangle); 562 dvmReleaseTrackedAlloc((Object*) params, NULL); 563 dvmReleaseTrackedAlloc((Object*) exceptions, NULL); 564 if (result == NULL) { 565 assert(dvmCheckException(dvmThreadSelf())); 566 dvmReleaseTrackedAlloc(consObj, NULL); 567 } 568 /* caller must dvmReleaseTrackedAlloc(result) */ 569 return result; 570 } 571 572 /* 573 * Get an array with all constructors declared by a class. 574 */ 575 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly) 576 { 577 ArrayObject* consArray; 578 Method* meth; 579 int i, count; 580 581 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 582 dvmInitClass(gDvm.classJavaLangReflectConstructor); 583 584 /* 585 * Ordinarily we init the class the first time we resolve a method. 586 * We're bypassing the normal resolution mechanism, so we init it here. 587 */ 588 if (!dvmIsClassInitialized(clazz)) 589 dvmInitClass(clazz); 590 591 /* 592 * Count up the #of relevant methods. 593 */ 594 count = 0; 595 meth = clazz->directMethods; 596 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 597 if ((!publicOnly || dvmIsPublicMethod(meth)) && 598 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 599 { 600 count++; 601 } 602 } 603 604 /* 605 * Create an array of Constructor objects. 606 */ 607 consArray = dvmAllocArray(gDvm.classJavaLangReflectConstructorArray, count, 608 kObjectArrayRefWidth, ALLOC_DEFAULT); 609 if (consArray == NULL) 610 return NULL; 611 612 /* 613 * Fill out the array. 614 */ 615 meth = clazz->directMethods; 616 size_t consObjCount = 0; 617 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 618 if ((!publicOnly || dvmIsPublicMethod(meth)) && 619 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 620 { 621 Object* consObj = createConstructorObject(meth); 622 if (consObj == NULL) 623 goto fail; 624 dvmSetObjectArrayElement(consArray, consObjCount, consObj); 625 ++consObjCount; 626 dvmReleaseTrackedAlloc(consObj, NULL); 627 } 628 } 629 630 assert(consObjCount == consArray->length); 631 632 /* caller must call dvmReleaseTrackedAlloc */ 633 return consArray; 634 635 fail: 636 dvmReleaseTrackedAlloc((Object*) consArray, NULL); 637 return NULL; 638 } 639 640 /* 641 * Create a new java/lang/reflect/Method object, using the contents of 642 * "meth" to construct it. 643 * 644 * The spec doesn't specify the constructor. We're going to use the 645 * one from our existing class libs: 646 * 647 * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes, 648 * Class returnType, String name, int slot) 649 * 650 * The caller must call dvmReleaseTrackedAlloc() on the result. 651 */ 652 Object* dvmCreateReflectMethodObject(const Method* meth) 653 { 654 Object* result = NULL; 655 ArrayObject* params = NULL; 656 ArrayObject* exceptions = NULL; 657 StringObject* nameObj = NULL; 658 Object* methObj; 659 ClassObject* returnType; 660 DexStringCache mangle; 661 char* cp; 662 int slot; 663 664 if (dvmCheckException(dvmThreadSelf())) { 665 LOGW("WARNING: dvmCreateReflectMethodObject called with " 666 "exception pending\n"); 667 return NULL; 668 } 669 670 dexStringCacheInit(&mangle); 671 672 /* parent should guarantee init so we don't have to check on every call */ 673 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)); 674 675 methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT); 676 if (methObj == NULL) 677 goto bail; 678 679 /* 680 * Convert the signature string into an array of classes representing 681 * the arguments, and a class for the return type. 682 */ 683 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); 684 params = convertSignatureToClassArray(&cp, meth->clazz); 685 if (params == NULL) 686 goto bail; 687 assert(*cp == ')'); 688 cp++; 689 returnType = convertSignaturePartToClass(&cp, meth->clazz); 690 if (returnType == NULL) 691 goto bail; 692 693 /* 694 * Create an array with one entry for every exception that the class 695 * is declared to throw. 696 */ 697 exceptions = dvmGetMethodThrows(meth); 698 if (dvmCheckException(dvmThreadSelf())) 699 goto bail; 700 701 /* method name */ 702 nameObj = dvmCreateStringFromCstr(meth->name); 703 if (nameObj == NULL) 704 goto bail; 705 706 slot = methodToSlot(meth); 707 708 JValue unused; 709 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init, 710 methObj, &unused, meth->clazz, params, exceptions, returnType, 711 nameObj, slot); 712 if (dvmCheckException(dvmThreadSelf())) { 713 LOGD("Method class init threw exception\n"); 714 goto bail; 715 } 716 717 result = methObj; 718 719 bail: 720 dexStringCacheRelease(&mangle); 721 if (result == NULL) { 722 assert(dvmCheckException(dvmThreadSelf())); 723 } 724 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 725 dvmReleaseTrackedAlloc((Object*) params, NULL); 726 dvmReleaseTrackedAlloc((Object*) exceptions, NULL); 727 if (result == NULL) 728 dvmReleaseTrackedAlloc(methObj, NULL); 729 return result; 730 } 731 732 /* 733 * Get an array with all methods declared by a class. 734 * 735 * This includes both static and virtual methods, and can include private 736 * members if "publicOnly" is false. It does not include Miranda methods, 737 * since those weren't declared in the class, or constructors. 738 */ 739 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly) 740 { 741 ArrayObject* methodArray; 742 Method* meth; 743 int i, count; 744 745 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 746 dvmInitClass(gDvm.classJavaLangReflectMethod); 747 748 /* 749 * Count up the #of relevant methods. 750 * 751 * Ignore virtual Miranda methods and direct class/object constructors. 752 */ 753 count = 0; 754 meth = clazz->virtualMethods; 755 for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { 756 if ((!publicOnly || dvmIsPublicMethod(meth)) && 757 !dvmIsMirandaMethod(meth)) 758 { 759 count++; 760 } 761 } 762 meth = clazz->directMethods; 763 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 764 if ((!publicOnly || dvmIsPublicMethod(meth)) && 765 meth->name[0] != '<') 766 { 767 count++; 768 } 769 } 770 771 /* 772 * Create an array of Method objects. 773 */ 774 methodArray = dvmAllocArray(gDvm.classJavaLangReflectMethodArray, count, 775 kObjectArrayRefWidth, ALLOC_DEFAULT); 776 if (methodArray == NULL) 777 return NULL; 778 779 780 /* 781 * Fill out the array. 782 */ 783 meth = clazz->virtualMethods; 784 size_t methObjCount = 0; 785 for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { 786 if ((!publicOnly || dvmIsPublicMethod(meth)) && 787 !dvmIsMirandaMethod(meth)) 788 { 789 Object* methObj = dvmCreateReflectMethodObject(meth); 790 if (methObj == NULL) 791 goto fail; 792 dvmSetObjectArrayElement(methodArray, methObjCount, methObj); 793 ++methObjCount; 794 dvmReleaseTrackedAlloc(methObj, NULL); 795 } 796 } 797 meth = clazz->directMethods; 798 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 799 if ((!publicOnly || dvmIsPublicMethod(meth)) && 800 meth->name[0] != '<') 801 { 802 Object* methObj = dvmCreateReflectMethodObject(meth); 803 if (methObj == NULL) 804 goto fail; 805 dvmSetObjectArrayElement(methodArray, methObjCount, methObj); 806 ++methObjCount; 807 dvmReleaseTrackedAlloc(methObj, NULL); 808 } 809 } 810 811 assert(methObjCount == methodArray->length); 812 813 /* caller must call dvmReleaseTrackedAlloc */ 814 return methodArray; 815 816 fail: 817 dvmReleaseTrackedAlloc((Object*) methodArray, NULL); 818 return NULL; 819 } 820 821 /* 822 * Get all interfaces a class implements. If this is unable to allocate 823 * the result array, this raises an OutOfMemoryError and returns NULL. 824 */ 825 ArrayObject* dvmGetInterfaces(ClassObject* clazz) 826 { 827 ArrayObject* interfaceArray; 828 829 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 830 dvmInitClass(gDvm.classJavaLangReflectMethod); 831 832 /* 833 * Create an array of Class objects. 834 */ 835 int count = clazz->interfaceCount; 836 interfaceArray = dvmAllocArray(gDvm.classJavaLangClassArray, count, 837 kObjectArrayRefWidth, ALLOC_DEFAULT); 838 if (interfaceArray == NULL) 839 return NULL; 840 841 /* 842 * Fill out the array. 843 */ 844 memcpy(interfaceArray->contents, clazz->interfaces, 845 count * sizeof(Object *)); 846 dvmWriteBarrierArray(interfaceArray, 0, count); 847 848 /* caller must call dvmReleaseTrackedAlloc */ 849 return interfaceArray; 850 } 851 852 /* 853 * Given a boxed primitive type, such as java/lang/Integer, return the 854 * primitive type index. 855 * 856 * Returns PRIM_NOT for void, since we never "box" that. 857 */ 858 static PrimitiveType getBoxedType(DataObject* arg) 859 { 860 static const int kJavaLangLen = 11; // strlen("Ljava/lang/") 861 const char* name; 862 863 if (arg == NULL) 864 return PRIM_NOT; 865 866 name = arg->obj.clazz->descriptor; 867 868 if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0) 869 return PRIM_NOT; 870 871 if (strcmp(name + kJavaLangLen, "Boolean;") == 0) 872 return PRIM_BOOLEAN; 873 if (strcmp(name + kJavaLangLen, "Character;") == 0) 874 return PRIM_CHAR; 875 if (strcmp(name + kJavaLangLen, "Float;") == 0) 876 return PRIM_FLOAT; 877 if (strcmp(name + kJavaLangLen, "Double;") == 0) 878 return PRIM_DOUBLE; 879 if (strcmp(name + kJavaLangLen, "Byte;") == 0) 880 return PRIM_BYTE; 881 if (strcmp(name + kJavaLangLen, "Short;") == 0) 882 return PRIM_SHORT; 883 if (strcmp(name + kJavaLangLen, "Integer;") == 0) 884 return PRIM_INT; 885 if (strcmp(name + kJavaLangLen, "Long;") == 0) 886 return PRIM_LONG; 887 return PRIM_NOT; 888 } 889 890 /* 891 * Convert primitive, boxed data from "srcPtr" to "dstPtr". 892 * 893 * Section v2 2.6 lists the various conversions and promotions. We 894 * allow the "widening" and "identity" conversions, but don't allow the 895 * "narrowing" conversions. 896 * 897 * Allowed: 898 * byte to short, int, long, float, double 899 * short to int, long, float double 900 * char to int, long, float, double 901 * int to long, float, double 902 * long to float, double 903 * float to double 904 * Values of types byte, char, and short are "internally" widened to int. 905 * 906 * Returns the width in bytes of the destination primitive, or -1 if the 907 * conversion is not allowed. 908 * 909 * TODO? use JValue rather than u4 pointers 910 */ 911 int dvmConvertPrimitiveValue(PrimitiveType srcType, 912 PrimitiveType dstType, const s4* srcPtr, s4* dstPtr) 913 { 914 enum { 915 OK4, OK8, ItoJ, 916 ItoD, JtoD, FtoD, 917 ItoF, JtoF, 918 bad, kMax 919 }; 920 /* [src][dst] */ 921 static const int kConvMode[kMax][kMax] = { 922 /*FROM *TO: bool char float double byte short int long */ 923 /*bool */ { OK4, bad, bad, bad, bad, bad, bad, bad }, 924 /*char */ { bad, OK4, ItoF, ItoD, bad, bad, OK4, ItoJ }, 925 /*float*/ { bad, bad, OK4, FtoD, bad, bad, bad, bad }, 926 /*doubl*/ { bad, bad, bad, OK8, bad, bad, bad, bad }, 927 /*byte */ { bad, bad, ItoF, ItoD, OK4, OK4, OK4, ItoJ }, 928 /*short*/ { bad, bad, ItoF, ItoD, bad, OK4, OK4, ItoJ }, 929 /*int */ { bad, bad, ItoF, ItoD, bad, bad, OK4, ItoJ }, 930 /*long */ { bad, bad, JtoF, JtoD, bad, bad, bad, OK8 }, 931 }; 932 int result; 933 934 assert(srcType != PRIM_NOT && dstType != PRIM_NOT && 935 srcType != PRIM_VOID && dstType != PRIM_VOID); 936 result = kConvMode[srcType][dstType]; 937 938 //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result); 939 940 switch (result) { 941 case OK4: 942 *dstPtr = *srcPtr; 943 return 1; 944 case OK8: 945 *(s8*)dstPtr = *(s8*)srcPtr; 946 return 2; 947 case ItoJ: 948 *(s8*)dstPtr = (s8) (*(s4*) srcPtr); 949 return 2; 950 case ItoD: 951 *(double*)dstPtr = (double) (*(s4*) srcPtr); 952 return 2; 953 case JtoD: 954 *(double*)dstPtr = (double) (*(long long*) srcPtr); 955 return 2; 956 case FtoD: 957 *(double*)dstPtr = (double) (*(float*) srcPtr); 958 return 2; 959 case ItoF: 960 *(float*)dstPtr = (float) (*(int*) srcPtr); 961 return 1; 962 case JtoF: 963 *(float*)dstPtr = (float) (*(long long*) srcPtr); 964 return 1; 965 case bad: 966 LOGV("convert primitive: prim %d to %d not allowed\n", 967 srcType, dstType); 968 return -1; 969 default: 970 assert(false); 971 return -1; 972 } 973 } 974 975 /* 976 * Convert types and widen primitives. Puts the value of "arg" into 977 * "destPtr". 978 * 979 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error. 980 */ 981 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) 982 { 983 int retVal; 984 985 if (dvmIsPrimitiveClass(type)) { 986 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */ 987 PrimitiveType srcType; 988 s4* valuePtr; 989 990 srcType = getBoxedType(arg); 991 if (srcType < 0) { // didn't pass a boxed primitive in 992 LOGVV("conv arg: type '%s' not boxed primitive\n", 993 arg->obj.clazz->descriptor); 994 return -1; 995 } 996 997 /* assumes value is stored in first instance field */ 998 valuePtr = (s4*) arg->instanceData; 999 1000 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType, 1001 valuePtr, destPtr); 1002 } else { 1003 /* verify object is compatible */ 1004 if ((arg == NULL) || dvmInstanceof(arg->obj.clazz, type)) { 1005 *destPtr = (s4) arg; 1006 retVal = 1; 1007 } else { 1008 LOGVV("Arg %p (%s) not compatible with %s\n", 1009 arg, arg->obj.clazz->descriptor, type->descriptor); 1010 retVal = -1; 1011 } 1012 } 1013 1014 return retVal; 1015 } 1016 1017 /* 1018 * Create a wrapper object for a primitive data type. If "returnType" is 1019 * not primitive, this just casts "value" to an object and returns it. 1020 * 1021 * We could invoke the "toValue" method on the box types to take 1022 * advantage of pre-created values, but running that through the 1023 * interpreter is probably less efficient than just allocating storage here. 1024 * 1025 * The caller must call dvmReleaseTrackedAlloc on the result. 1026 */ 1027 DataObject* dvmWrapPrimitive(JValue value, ClassObject* returnType) 1028 { 1029 static const char* boxTypes[] = { // order from enum PrimitiveType 1030 "Ljava/lang/Boolean;", 1031 "Ljava/lang/Character;", 1032 "Ljava/lang/Float;", 1033 "Ljava/lang/Double;", 1034 "Ljava/lang/Byte;", 1035 "Ljava/lang/Short;", 1036 "Ljava/lang/Integer;", 1037 "Ljava/lang/Long;" 1038 }; 1039 ClassObject* wrapperClass; 1040 DataObject* wrapperObj; 1041 s4* dataPtr; 1042 PrimitiveType typeIndex = returnType->primitiveType; 1043 const char* classDescriptor; 1044 1045 if (typeIndex == PRIM_NOT) { 1046 /* add to tracking table so return value is always in table */ 1047 if (value.l != NULL) 1048 dvmAddTrackedAlloc(value.l, NULL); 1049 return (DataObject*) value.l; 1050 } 1051 1052 assert(typeIndex >= 0 && typeIndex < PRIM_MAX); 1053 if (typeIndex == PRIM_VOID) 1054 return NULL; 1055 1056 classDescriptor = boxTypes[typeIndex]; 1057 1058 wrapperClass = dvmFindSystemClass(classDescriptor); 1059 if (wrapperClass == NULL) { 1060 LOGW("Unable to find '%s'\n", classDescriptor); 1061 assert(dvmCheckException(dvmThreadSelf())); 1062 return NULL; 1063 } 1064 1065 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); 1066 if (wrapperObj == NULL) 1067 return NULL; 1068 dataPtr = (s4*) wrapperObj->instanceData; 1069 1070 /* assumes value is stored in first instance field */ 1071 /* (see dvmValidateBoxClasses) */ 1072 if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) 1073 *(s8*)dataPtr = value.j; 1074 else 1075 *dataPtr = value.i; 1076 1077 return wrapperObj; 1078 } 1079 1080 /* 1081 * Unwrap a primitive data type, if necessary. 1082 * 1083 * If "returnType" is not primitive, we just tuck "value" into JValue and 1084 * return it after verifying that it's the right type of object. 1085 * 1086 * Fails if the field is primitive and "value" is either not a boxed 1087 * primitive or is of a type that cannot be converted. 1088 * 1089 * Returns "true" on success, "false" on failure. 1090 */ 1091 bool dvmUnwrapPrimitive(Object* value, ClassObject* returnType, 1092 JValue* pResult) 1093 { 1094 PrimitiveType typeIndex = returnType->primitiveType; 1095 PrimitiveType valueIndex; 1096 1097 if (typeIndex == PRIM_NOT) { 1098 if (value != NULL && !dvmInstanceof(value->clazz, returnType)) { 1099 LOGD("wrong object type: %s %s\n", 1100 value->clazz->descriptor, returnType->descriptor); 1101 return false; 1102 } 1103 pResult->l = value; 1104 return true; 1105 } else if (typeIndex == PRIM_VOID) { 1106 /* can't put anything into a void */ 1107 return false; 1108 } 1109 1110 valueIndex = getBoxedType((DataObject*)value); 1111 if (valueIndex == PRIM_NOT) 1112 return false; 1113 1114 /* assumes value is stored in first instance field of "value" */ 1115 /* (see dvmValidateBoxClasses) */ 1116 if (dvmConvertPrimitiveValue(valueIndex, typeIndex, 1117 (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0) 1118 { 1119 LOGV("Prim conversion failed\n"); 1120 return false; 1121 } 1122 1123 return true; 1124 } 1125 1126 1127 /* 1128 * Find the return type in the signature, and convert it to a class 1129 * object. For primitive types we use a boxed class, for reference types 1130 * we do a name lookup. 1131 * 1132 * On failure, we return NULL with an exception raised. 1133 */ 1134 ClassObject* dvmGetBoxedReturnType(const Method* meth) 1135 { 1136 const char* sig = dexProtoGetReturnType(&meth->prototype); 1137 1138 switch (*sig) { 1139 case 'Z': 1140 case 'C': 1141 case 'F': 1142 case 'D': 1143 case 'B': 1144 case 'S': 1145 case 'I': 1146 case 'J': 1147 case 'V': 1148 return dvmFindPrimitiveClass(*sig); 1149 case '[': 1150 case 'L': 1151 return dvmFindClass(sig, meth->clazz->classLoader); 1152 default: { 1153 /* should not have passed verification */ 1154 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1155 LOGE("Bad return type in signature '%s'\n", desc); 1156 free(desc); 1157 dvmThrowException("Ljava/lang/InternalError;", NULL); 1158 return NULL; 1159 } 1160 } 1161 } 1162 1163 1164 /* 1165 * JNI reflection support: convert reflection object to Field ptr. 1166 */ 1167 Field* dvmGetFieldFromReflectObj(Object* obj) 1168 { 1169 ClassObject* clazz; 1170 int slot; 1171 1172 assert(obj->clazz == gDvm.classJavaLangReflectField); 1173 clazz = (ClassObject*)dvmGetFieldObject(obj, 1174 gDvm.offJavaLangReflectField_declClass); 1175 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot); 1176 1177 /* must initialize the class before returning a field ID */ 1178 if (!dvmInitClass(clazz)) 1179 return NULL; 1180 1181 return dvmSlotToField(clazz, slot); 1182 } 1183 1184 /* 1185 * JNI reflection support: convert reflection object to Method ptr. 1186 */ 1187 Method* dvmGetMethodFromReflectObj(Object* obj) 1188 { 1189 ClassObject* clazz; 1190 int slot; 1191 1192 if (obj->clazz == gDvm.classJavaLangReflectConstructor) { 1193 clazz = (ClassObject*)dvmGetFieldObject(obj, 1194 gDvm.offJavaLangReflectConstructor_declClass); 1195 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot); 1196 } else if (obj->clazz == gDvm.classJavaLangReflectMethod) { 1197 clazz = (ClassObject*)dvmGetFieldObject(obj, 1198 gDvm.offJavaLangReflectMethod_declClass); 1199 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot); 1200 } else { 1201 assert(false); 1202 return NULL; 1203 } 1204 1205 /* must initialize the class before returning a method ID */ 1206 if (!dvmInitClass(clazz)) 1207 return NULL; 1208 1209 return dvmSlotToMethod(clazz, slot); 1210 } 1211 1212 /* 1213 * JNI reflection support: convert Field to reflection object. 1214 * 1215 * The return value is a java.lang.reflect.Field. 1216 * 1217 * Caller must call dvmReleaseTrackedAlloc(). 1218 */ 1219 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field) 1220 { 1221 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 1222 dvmInitClass(gDvm.classJavaLangReflectField); 1223 1224 /* caller must dvmReleaseTrackedAlloc(result) */ 1225 return createFieldObject(field, clazz); 1226 } 1227 1228 /* 1229 * JNI reflection support: convert Method to reflection object. 1230 * 1231 * The returned object will be either a java.lang.reflect.Method or 1232 * .Constructor, depending on whether "method" is a constructor. 1233 * 1234 * This is also used for certain "system" annotations. 1235 * 1236 * Caller must call dvmReleaseTrackedAlloc(). 1237 */ 1238 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method) 1239 { 1240 UNUSED_PARAMETER(clazz); 1241 1242 if (strcmp(method->name, "<init>") == 0) { 1243 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 1244 dvmInitClass(gDvm.classJavaLangReflectConstructor); 1245 1246 return createConstructorObject(method); 1247 } else { 1248 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 1249 dvmInitClass(gDvm.classJavaLangReflectMethod); 1250 1251 return dvmCreateReflectMethodObject(method); 1252 } 1253 } 1254