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 ClassObject** classes; 244 char* signature = *pSignature; 245 char* cp; 246 int i, count; 247 248 assert(*signature == '('); 249 signature++; 250 251 /* count up the number of parameters */ 252 count = 0; 253 cp = signature; 254 while (*cp != ')') { 255 count++; 256 257 if (*cp == '[') { 258 while (*++cp == '[') 259 ; 260 } 261 if (*cp == 'L') { 262 while (*++cp != ';') 263 ; 264 } 265 cp++; 266 } 267 LOGVV("REFLECT found %d parameters in '%s'\n", count, *pSignature); 268 269 /* create an array to hold them */ 270 classArray = dvmAllocArray(gDvm.classJavaLangClassArray, count, 271 kObjectArrayRefWidth, ALLOC_DEFAULT); 272 if (classArray == NULL) 273 return NULL; 274 275 /* fill it in */ 276 classes = (ClassObject**) classArray->contents; 277 cp = signature; 278 for (i = 0; i < count; i++) { 279 ClassObject* clazz; 280 281 clazz = convertSignaturePartToClass(&cp, defClass); 282 if (clazz == NULL) { 283 assert(dvmCheckException(dvmThreadSelf())); 284 return NULL; 285 } 286 LOGVV("REFLECT %d: '%s'\n", i, clazz->descriptor); 287 288 *classes++ = clazz; 289 } 290 291 *pSignature = cp; 292 293 /* caller must call dvmReleaseTrackedAlloc */ 294 return classArray; 295 } 296 297 298 /* 299 * Convert a field pointer to a slot number. 300 * 301 * We use positive values starting from 0 for instance fields, negative 302 * values starting from -1 for static fields. 303 */ 304 static int fieldToSlot(const Field* field, const ClassObject* clazz) 305 { 306 int slot; 307 308 if (dvmIsStaticField(field)) { 309 slot = (StaticField*)field - clazz->sfields; 310 assert(slot >= 0 && slot < clazz->sfieldCount); 311 slot = -(slot+1); 312 } else { 313 slot = (InstField*)field - clazz->ifields; 314 assert(slot >= 0 && slot < clazz->ifieldCount); 315 } 316 317 return slot; 318 } 319 320 /* 321 * Convert a slot number to a field pointer. 322 */ 323 Field* dvmSlotToField(ClassObject* clazz, int slot) 324 { 325 if (slot < 0) { 326 slot = -(slot+1); 327 assert(slot < clazz->sfieldCount); 328 return (Field*) &clazz->sfields[slot]; 329 } else { 330 assert(slot < clazz->ifieldCount); 331 return (Field*) &clazz->ifields[slot]; 332 } 333 } 334 335 /* 336 * Create a new java.lang.reflect.Field object from "field". 337 * 338 * The Field spec doesn't specify the constructor. We're going to use the 339 * one from our existing class libs: 340 * 341 * private Field(Class declaringClass, Class type, String name, int slot) 342 */ 343 static Object* createFieldObject(Field* field, const ClassObject* clazz) 344 { 345 Object* result = NULL; 346 Object* fieldObj = NULL; 347 StringObject* nameObj = NULL; 348 ClassObject* type; 349 char* mangle; 350 char* cp; 351 int slot; 352 353 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField)); 354 355 fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT); 356 if (fieldObj == NULL) 357 goto bail; 358 359 cp = mangle = strdup(field->signature); 360 type = convertSignaturePartToClass(&cp, clazz); 361 free(mangle); 362 if (type == NULL) 363 goto bail; 364 365 nameObj = dvmCreateStringFromCstr(field->name, ALLOC_DEFAULT); 366 if (nameObj == NULL) 367 goto bail; 368 369 slot = fieldToSlot(field, clazz); 370 371 JValue unused; 372 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init, 373 fieldObj, &unused, clazz, type, nameObj, slot); 374 if (dvmCheckException(dvmThreadSelf())) { 375 LOGD("Field class init threw exception\n"); 376 goto bail; 377 } 378 379 result = fieldObj; 380 381 bail: 382 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 383 if (result == NULL) 384 dvmReleaseTrackedAlloc((Object*) fieldObj, NULL); 385 /* caller must dvmReleaseTrackedAlloc(result) */ 386 return result; 387 } 388 389 /* 390 * 391 * Get an array with all fields declared by a class. 392 * 393 * This includes both static and instance fields. 394 */ 395 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly) 396 { 397 ArrayObject* fieldArray = NULL; 398 Object** fields; 399 int i, count; 400 401 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 402 dvmInitClass(gDvm.classJavaLangReflectField); 403 404 /* count #of fields */ 405 if (!publicOnly) 406 count = clazz->sfieldCount + clazz->ifieldCount; 407 else { 408 count = 0; 409 for (i = 0; i < clazz->sfieldCount; i++) { 410 if ((clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) 411 count++; 412 } 413 for (i = 0; i < clazz->ifieldCount; i++) { 414 if ((clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) 415 count++; 416 } 417 } 418 419 /* create the Field[] array */ 420 fieldArray = dvmAllocArray(gDvm.classJavaLangReflectFieldArray, count, 421 kObjectArrayRefWidth, ALLOC_DEFAULT); 422 if (fieldArray == NULL) 423 return NULL; 424 fields = (Object**) fieldArray->contents; 425 426 /* populate */ 427 for (i = 0; i < clazz->sfieldCount; i++) { 428 if (!publicOnly || 429 (clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) 430 { 431 *fields = createFieldObject(&clazz->sfields[i].field, clazz); 432 if (*fields == NULL) 433 goto fail; 434 dvmReleaseTrackedAlloc(*fields, NULL); 435 fields++; 436 count--; 437 } 438 } 439 for (i = 0; i < clazz->ifieldCount; i++) { 440 if (!publicOnly || 441 (clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) 442 { 443 *fields = createFieldObject(&clazz->ifields[i].field, clazz); 444 if (*fields == NULL) 445 goto fail; 446 dvmReleaseTrackedAlloc(*fields, NULL); 447 fields++; 448 count--; 449 } 450 } 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 Object** consObjPtr; 579 Method* meth; 580 int i, count; 581 582 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 583 dvmInitClass(gDvm.classJavaLangReflectConstructor); 584 585 /* 586 * Ordinarily we init the class the first time we resolve a method. 587 * We're bypassing the normal resolution mechanism, so we init it here. 588 */ 589 if (!dvmIsClassInitialized(clazz)) 590 dvmInitClass(clazz); 591 592 /* 593 * Count up the #of relevant methods. 594 */ 595 count = 0; 596 meth = clazz->directMethods; 597 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 598 if ((!publicOnly || dvmIsPublicMethod(meth)) && 599 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 600 { 601 count++; 602 } 603 } 604 605 /* 606 * Create an array of Constructor objects. 607 */ 608 consArray = dvmAllocArray(gDvm.classJavaLangReflectConstructorArray, count, 609 kObjectArrayRefWidth, ALLOC_DEFAULT); 610 if (consArray == NULL) 611 return NULL; 612 613 consObjPtr = (Object**) consArray->contents; 614 615 /* 616 * Fill out the array. 617 */ 618 meth = clazz->directMethods; 619 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 620 if ((!publicOnly || dvmIsPublicMethod(meth)) && 621 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) 622 { 623 Object* consObj = createConstructorObject(meth); 624 if (consObj == NULL) 625 goto fail; 626 *consObjPtr++ = consObj; 627 dvmReleaseTrackedAlloc(consObj, NULL); 628 } 629 } 630 631 assert(consObjPtr - (Object**) consArray->contents == count); 632 633 /* caller must call dvmReleaseTrackedAlloc */ 634 return consArray; 635 636 fail: 637 dvmReleaseTrackedAlloc((Object*) consArray, NULL); 638 return NULL; 639 } 640 641 /* 642 * Create a new java/lang/reflect/Method object, using the contents of 643 * "meth" to construct it. 644 * 645 * The spec doesn't specify the constructor. We're going to use the 646 * one from our existing class libs: 647 * 648 * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes, 649 * Class returnType, String name, int slot) 650 * 651 * The caller must call dvmReleaseTrackedAlloc() on the result. 652 */ 653 Object* dvmCreateReflectMethodObject(const Method* meth) 654 { 655 Object* result = NULL; 656 ArrayObject* params = NULL; 657 ArrayObject* exceptions = NULL; 658 StringObject* nameObj = NULL; 659 Object* methObj; 660 ClassObject* returnType; 661 DexStringCache mangle; 662 char* cp; 663 int slot; 664 665 if (dvmCheckException(dvmThreadSelf())) { 666 LOGW("WARNING: dvmCreateReflectMethodObject called with " 667 "exception pending\n"); 668 return NULL; 669 } 670 671 dexStringCacheInit(&mangle); 672 673 /* parent should guarantee init so we don't have to check on every call */ 674 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)); 675 676 methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT); 677 if (methObj == NULL) 678 goto bail; 679 680 /* 681 * Convert the signature string into an array of classes representing 682 * the arguments, and a class for the return type. 683 */ 684 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); 685 params = convertSignatureToClassArray(&cp, meth->clazz); 686 if (params == NULL) 687 goto bail; 688 assert(*cp == ')'); 689 cp++; 690 returnType = convertSignaturePartToClass(&cp, meth->clazz); 691 if (returnType == NULL) 692 goto bail; 693 694 /* 695 * Create an array with one entry for every exception that the class 696 * is declared to throw. 697 */ 698 exceptions = dvmGetMethodThrows(meth); 699 if (dvmCheckException(dvmThreadSelf())) 700 goto bail; 701 702 /* method name */ 703 nameObj = dvmCreateStringFromCstr(meth->name, ALLOC_DEFAULT); 704 if (nameObj == NULL) 705 goto bail; 706 707 slot = methodToSlot(meth); 708 709 JValue unused; 710 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init, 711 methObj, &unused, meth->clazz, params, exceptions, returnType, 712 nameObj, slot); 713 if (dvmCheckException(dvmThreadSelf())) { 714 LOGD("Method class init threw exception\n"); 715 goto bail; 716 } 717 718 result = methObj; 719 720 bail: 721 dexStringCacheRelease(&mangle); 722 if (result == NULL) { 723 assert(dvmCheckException(dvmThreadSelf())); 724 } 725 dvmReleaseTrackedAlloc((Object*) nameObj, NULL); 726 dvmReleaseTrackedAlloc((Object*) params, NULL); 727 dvmReleaseTrackedAlloc((Object*) exceptions, NULL); 728 if (result == NULL) 729 dvmReleaseTrackedAlloc(methObj, NULL); 730 return result; 731 } 732 733 /* 734 * Get an array with all methods declared by a class. 735 * 736 * This includes both static and virtual methods, and can include private 737 * members if "publicOnly" is false. It does not include Miranda methods, 738 * since those weren't declared in the class, or constructors. 739 */ 740 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly) 741 { 742 ArrayObject* methodArray; 743 Object** methObjPtr; 744 Method* meth; 745 int i, count; 746 747 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 748 dvmInitClass(gDvm.classJavaLangReflectMethod); 749 750 /* 751 * Count up the #of relevant methods. 752 * 753 * Ignore virtual Miranda methods and direct class/object constructors. 754 */ 755 count = 0; 756 meth = clazz->virtualMethods; 757 for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { 758 if ((!publicOnly || dvmIsPublicMethod(meth)) && 759 !dvmIsMirandaMethod(meth)) 760 { 761 count++; 762 } 763 } 764 meth = clazz->directMethods; 765 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 766 if ((!publicOnly || dvmIsPublicMethod(meth)) && 767 meth->name[0] != '<') 768 { 769 count++; 770 } 771 } 772 773 /* 774 * Create an array of Method objects. 775 */ 776 methodArray = dvmAllocArray(gDvm.classJavaLangReflectMethodArray, count, 777 kObjectArrayRefWidth, ALLOC_DEFAULT); 778 if (methodArray == NULL) 779 return NULL; 780 781 methObjPtr = (Object**) methodArray->contents; 782 783 /* 784 * Fill out the array. 785 */ 786 meth = clazz->virtualMethods; 787 for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { 788 if ((!publicOnly || dvmIsPublicMethod(meth)) && 789 !dvmIsMirandaMethod(meth)) 790 { 791 Object* methObj = dvmCreateReflectMethodObject(meth); 792 if (methObj == NULL) 793 goto fail; 794 *methObjPtr++ = methObj; 795 dvmReleaseTrackedAlloc(methObj, NULL); 796 } 797 } 798 meth = clazz->directMethods; 799 for (i = 0; i < clazz->directMethodCount; i++, meth++) { 800 if ((!publicOnly || dvmIsPublicMethod(meth)) && 801 meth->name[0] != '<') 802 { 803 Object* methObj = dvmCreateReflectMethodObject(meth); 804 if (methObj == NULL) 805 goto fail; 806 *methObjPtr++ = methObj; 807 dvmReleaseTrackedAlloc(methObj, NULL); 808 } 809 } 810 811 assert(methObjPtr - (Object**) methodArray->contents == count); 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 Object** interfaceObjPtr = (Object**) interfaceArray->contents; 845 int i; 846 for (i = 0; i < count; i++) { 847 *interfaceObjPtr++ = (Object*) clazz->interfaces[i]; 848 } 849 850 /* caller must call dvmReleaseTrackedAlloc */ 851 return interfaceArray; 852 } 853 854 /* 855 * Given a boxed primitive type, such as java/lang/Integer, return the 856 * primitive type index. 857 * 858 * Returns PRIM_NOT for void, since we never "box" that. 859 */ 860 static PrimitiveType getBoxedType(DataObject* arg) 861 { 862 static const int kJavaLangLen = 11; // strlen("Ljava/lang/") 863 const char* name; 864 865 if (arg == NULL) 866 return PRIM_NOT; 867 868 name = arg->obj.clazz->descriptor; 869 870 if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0) 871 return PRIM_NOT; 872 873 if (strcmp(name + kJavaLangLen, "Boolean;") == 0) 874 return PRIM_BOOLEAN; 875 if (strcmp(name + kJavaLangLen, "Character;") == 0) 876 return PRIM_CHAR; 877 if (strcmp(name + kJavaLangLen, "Float;") == 0) 878 return PRIM_FLOAT; 879 if (strcmp(name + kJavaLangLen, "Double;") == 0) 880 return PRIM_DOUBLE; 881 if (strcmp(name + kJavaLangLen, "Byte;") == 0) 882 return PRIM_BYTE; 883 if (strcmp(name + kJavaLangLen, "Short;") == 0) 884 return PRIM_SHORT; 885 if (strcmp(name + kJavaLangLen, "Integer;") == 0) 886 return PRIM_INT; 887 if (strcmp(name + kJavaLangLen, "Long;") == 0) 888 return PRIM_LONG; 889 return PRIM_NOT; 890 } 891 892 /* 893 * Convert primitive, boxed data from "srcPtr" to "dstPtr". 894 * 895 * Section v2 2.6 lists the various conversions and promotions. We 896 * allow the "widening" and "identity" conversions, but don't allow the 897 * "narrowing" conversions. 898 * 899 * Allowed: 900 * byte to short, int, long, float, double 901 * short to int, long, float double 902 * char to int, long, float, double 903 * int to long, float, double 904 * long to float, double 905 * float to double 906 * Values of types byte, char, and short are "internally" widened to int. 907 * 908 * Returns the width in bytes of the destination primitive, or -1 if the 909 * conversion is not allowed. 910 * 911 * TODO? use JValue rather than u4 pointers 912 */ 913 int dvmConvertPrimitiveValue(PrimitiveType srcType, 914 PrimitiveType dstType, const s4* srcPtr, s4* dstPtr) 915 { 916 enum { 917 OK4, OK8, ItoJ, 918 ItoD, JtoD, FtoD, 919 ItoF, JtoF, 920 bad, kMax 921 }; 922 /* [src][dst] */ 923 static const int kConvMode[kMax][kMax] = { 924 /*FROM *TO: bool char float double byte short int long */ 925 /*bool */ { OK4, bad, bad, bad, bad, bad, bad, bad }, 926 /*char */ { bad, OK4, ItoF, ItoD, bad, bad, OK4, ItoJ }, 927 /*float*/ { bad, bad, OK4, FtoD, bad, bad, bad, bad }, 928 /*doubl*/ { bad, bad, bad, OK8, bad, bad, bad, bad }, 929 /*byte */ { bad, bad, ItoF, ItoD, OK4, OK4, OK4, ItoJ }, 930 /*short*/ { bad, bad, ItoF, ItoD, bad, OK4, OK4, ItoJ }, 931 /*int */ { bad, bad, ItoF, ItoD, bad, bad, OK4, ItoJ }, 932 /*long */ { bad, bad, JtoF, JtoD, bad, bad, bad, OK8 }, 933 }; 934 int result; 935 936 assert(srcType != PRIM_NOT && dstType != PRIM_NOT && 937 srcType != PRIM_VOID && dstType != PRIM_VOID); 938 result = kConvMode[srcType][dstType]; 939 940 //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result); 941 942 switch (result) { 943 case OK4: 944 *dstPtr = *srcPtr; 945 return 1; 946 case OK8: 947 *(s8*)dstPtr = *(s8*)srcPtr; 948 return 2; 949 case ItoJ: 950 *(s8*)dstPtr = (s8) (*(s4*) srcPtr); 951 return 2; 952 case ItoD: 953 *(double*)dstPtr = (double) (*(s4*) srcPtr); 954 return 2; 955 case JtoD: 956 *(double*)dstPtr = (double) (*(long long*) srcPtr); 957 return 2; 958 case FtoD: 959 *(double*)dstPtr = (double) (*(float*) srcPtr); 960 return 2; 961 case ItoF: 962 *(float*)dstPtr = (float) (*(int*) srcPtr); 963 return 1; 964 case JtoF: 965 *(float*)dstPtr = (float) (*(long long*) srcPtr); 966 return 1; 967 case bad: 968 LOGV("convert primitive: prim %d to %d not allowed\n", 969 srcType, dstType); 970 return -1; 971 default: 972 assert(false); 973 return -1; 974 } 975 } 976 977 /* 978 * Convert types and widen primitives. Puts the value of "arg" into 979 * "destPtr". 980 * 981 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error. 982 */ 983 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) 984 { 985 int retVal; 986 987 if (dvmIsPrimitiveClass(type)) { 988 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */ 989 PrimitiveType srcType; 990 s4* valuePtr; 991 992 srcType = getBoxedType(arg); 993 if (srcType < 0) { // didn't pass a boxed primitive in 994 LOGVV("conv arg: type '%s' not boxed primitive\n", 995 arg->obj.clazz->descriptor); 996 return -1; 997 } 998 999 /* assumes value is stored in first instance field */ 1000 valuePtr = (s4*) arg->instanceData; 1001 1002 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType, 1003 valuePtr, destPtr); 1004 } else { 1005 /* verify object is compatible */ 1006 if ((arg == NULL) || dvmInstanceof(arg->obj.clazz, type)) { 1007 *destPtr = (s4) arg; 1008 retVal = 1; 1009 } else { 1010 LOGVV("Arg %p (%s) not compatible with %s\n", 1011 arg, arg->obj.clazz->descriptor, type->descriptor); 1012 retVal = -1; 1013 } 1014 } 1015 1016 return retVal; 1017 } 1018 1019 /* 1020 * Create a wrapper object for a primitive data type. If "returnType" is 1021 * not primitive, this just casts "value" to an object and returns it. 1022 * 1023 * We could invoke the "toValue" method on the box types to take 1024 * advantage of pre-created values, but running that through the 1025 * interpreter is probably less efficient than just allocating storage here. 1026 * 1027 * The caller must call dvmReleaseTrackedAlloc on the result. 1028 */ 1029 DataObject* dvmWrapPrimitive(JValue value, ClassObject* returnType) 1030 { 1031 static const char* boxTypes[] = { // order from enum PrimitiveType 1032 "Ljava/lang/Boolean;", 1033 "Ljava/lang/Character;", 1034 "Ljava/lang/Float;", 1035 "Ljava/lang/Double;", 1036 "Ljava/lang/Byte;", 1037 "Ljava/lang/Short;", 1038 "Ljava/lang/Integer;", 1039 "Ljava/lang/Long;" 1040 }; 1041 ClassObject* wrapperClass; 1042 DataObject* wrapperObj; 1043 s4* dataPtr; 1044 PrimitiveType typeIndex = returnType->primitiveType; 1045 const char* classDescriptor; 1046 1047 if (typeIndex == PRIM_NOT) { 1048 /* add to tracking table so return value is always in table */ 1049 if (value.l != NULL) 1050 dvmAddTrackedAlloc(value.l, NULL); 1051 return (DataObject*) value.l; 1052 } 1053 1054 assert(typeIndex >= 0 && typeIndex < PRIM_MAX); 1055 if (typeIndex == PRIM_VOID) 1056 return NULL; 1057 1058 classDescriptor = boxTypes[typeIndex]; 1059 1060 wrapperClass = dvmFindSystemClass(classDescriptor); 1061 if (wrapperClass == NULL) { 1062 LOGW("Unable to find '%s'\n", classDescriptor); 1063 assert(dvmCheckException(dvmThreadSelf())); 1064 return NULL; 1065 } 1066 1067 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); 1068 if (wrapperObj == NULL) 1069 return NULL; 1070 dataPtr = (s4*) wrapperObj->instanceData; 1071 1072 /* assumes value is stored in first instance field */ 1073 /* (see dvmValidateBoxClasses) */ 1074 if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) 1075 *(s8*)dataPtr = value.j; 1076 else 1077 *dataPtr = value.i; 1078 1079 return wrapperObj; 1080 } 1081 1082 /* 1083 * Unwrap a primitive data type, if necessary. 1084 * 1085 * If "returnType" is not primitive, we just tuck "value" into JValue and 1086 * return it after verifying that it's the right type of object. 1087 * 1088 * Fails if the field is primitive and "value" is either not a boxed 1089 * primitive or is of a type that cannot be converted. 1090 * 1091 * Returns "true" on success, "false" on failure. 1092 */ 1093 bool dvmUnwrapPrimitive(Object* value, ClassObject* returnType, 1094 JValue* pResult) 1095 { 1096 JValue result; 1097 PrimitiveType typeIndex = returnType->primitiveType; 1098 PrimitiveType valueIndex; 1099 //const u4* dataPtr; 1100 1101 if (typeIndex == PRIM_NOT) { 1102 if (value != NULL && !dvmInstanceof(value->clazz, returnType)) { 1103 LOGD("wrong object type: %s %s\n", 1104 value->clazz->descriptor, returnType->descriptor); 1105 return false; 1106 } 1107 pResult->l = value; 1108 return true; 1109 } else if (typeIndex == PRIM_VOID) { 1110 /* can't put anything into a void */ 1111 return false; 1112 } 1113 1114 valueIndex = getBoxedType((DataObject*)value); 1115 if (valueIndex == PRIM_NOT) 1116 return false; 1117 1118 /* assumes value is stored in first instance field of "value" */ 1119 /* (see dvmValidateBoxClasses) */ 1120 if (dvmConvertPrimitiveValue(valueIndex, typeIndex, 1121 (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0) 1122 { 1123 LOGV("Prim conversion failed\n"); 1124 return false; 1125 } 1126 1127 return true; 1128 } 1129 1130 1131 /* 1132 * Find the return type in the signature, and convert it to a class 1133 * object. For primitive types we use a boxed class, for reference types 1134 * we do a name lookup. 1135 * 1136 * On failure, we return NULL with an exception raised. 1137 */ 1138 ClassObject* dvmGetBoxedReturnType(const Method* meth) 1139 { 1140 const char* sig = dexProtoGetReturnType(&meth->prototype); 1141 1142 switch (*sig) { 1143 case 'Z': 1144 case 'C': 1145 case 'F': 1146 case 'D': 1147 case 'B': 1148 case 'S': 1149 case 'I': 1150 case 'J': 1151 case 'V': 1152 return dvmFindPrimitiveClass(*sig); 1153 case '[': 1154 case 'L': 1155 return dvmFindClass(sig, meth->clazz->classLoader); 1156 default: { 1157 /* should not have passed verification */ 1158 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1159 LOGE("Bad return type in signature '%s'\n", desc); 1160 free(desc); 1161 dvmThrowException("Ljava/lang/InternalError;", NULL); 1162 return NULL; 1163 } 1164 } 1165 } 1166 1167 1168 /* 1169 * JNI reflection support: convert reflection object to Field ptr. 1170 */ 1171 Field* dvmGetFieldFromReflectObj(Object* obj) 1172 { 1173 ClassObject* clazz; 1174 int slot; 1175 1176 assert(obj->clazz == gDvm.classJavaLangReflectField); 1177 clazz = (ClassObject*)dvmGetFieldObject(obj, 1178 gDvm.offJavaLangReflectField_declClass); 1179 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot); 1180 1181 /* must initialize the class before returning a field ID */ 1182 if (!dvmInitClass(clazz)) 1183 return NULL; 1184 1185 return dvmSlotToField(clazz, slot); 1186 } 1187 1188 /* 1189 * JNI reflection support: convert reflection object to Method ptr. 1190 */ 1191 Method* dvmGetMethodFromReflectObj(Object* obj) 1192 { 1193 ClassObject* clazz; 1194 int slot; 1195 1196 if (obj->clazz == gDvm.classJavaLangReflectConstructor) { 1197 clazz = (ClassObject*)dvmGetFieldObject(obj, 1198 gDvm.offJavaLangReflectConstructor_declClass); 1199 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot); 1200 } else if (obj->clazz == gDvm.classJavaLangReflectMethod) { 1201 clazz = (ClassObject*)dvmGetFieldObject(obj, 1202 gDvm.offJavaLangReflectMethod_declClass); 1203 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot); 1204 } else { 1205 assert(false); 1206 return NULL; 1207 } 1208 1209 /* must initialize the class before returning a method ID */ 1210 if (!dvmInitClass(clazz)) 1211 return NULL; 1212 1213 return dvmSlotToMethod(clazz, slot); 1214 } 1215 1216 /* 1217 * JNI reflection support: convert Field to reflection object. 1218 * 1219 * The return value is a java.lang.reflect.Field. 1220 * 1221 * Caller must call dvmReleaseTrackedAlloc(). 1222 */ 1223 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field) 1224 { 1225 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) 1226 dvmInitClass(gDvm.classJavaLangReflectField); 1227 1228 /* caller must dvmReleaseTrackedAlloc(result) */ 1229 return createFieldObject(field, clazz); 1230 } 1231 1232 /* 1233 * JNI reflection support: convert Method to reflection object. 1234 * 1235 * The returned object will be either a java.lang.reflect.Method or 1236 * .Constructor, depending on whether "method" is a constructor. 1237 * 1238 * This is also used for certain "system" annotations. 1239 * 1240 * Caller must call dvmReleaseTrackedAlloc(). 1241 */ 1242 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method) 1243 { 1244 UNUSED_PARAMETER(clazz); 1245 1246 if (strcmp(method->name, "<init>") == 0) { 1247 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) 1248 dvmInitClass(gDvm.classJavaLangReflectConstructor); 1249 1250 return createConstructorObject(method); 1251 } else { 1252 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) 1253 dvmInitClass(gDvm.classJavaLangReflectMethod); 1254 1255 return dvmCreateReflectMethodObject(method); 1256 } 1257 } 1258 1259