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