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