• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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  */
dvmGetDeclaredFields(ClassObject * clazz,bool publicOnly)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  */
methodToSlot(const Method * meth)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  */
dvmSlotToMethod(ClassObject * clazz,int slot)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  */
createConstructorObject(Method * meth)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  */
dvmGetDeclaredConstructors(ClassObject * clazz,bool publicOnly)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  */
dvmCreateReflectMethodObject(const Method * meth)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  */
dvmGetDeclaredMethods(ClassObject * clazz,bool publicOnly)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  */
createTargetDescriptor(ArrayObject * args,DexStringCache * targetDescriptorCache)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 
findConstructorOrMethodInArray(int methodsCount,Method * methods,const char * name,const char * parameterDescriptors)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  */
dvmGetDeclaredConstructorOrMethod(ClassObject * clazz,StringObject * nameObj,ArrayObject * args)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  */
dvmGetDeclaredField(ClassObject * clazz,StringObject * nameObj)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  */
dvmGetInterfaces(ClassObject * clazz)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  */
getBoxedType(DataObject * arg)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  */
dvmConvertPrimitiveValue(PrimitiveType srcType,PrimitiveType dstType,const s4 * srcPtr,s4 * dstPtr)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  */
dvmConvertArgument(DataObject * arg,ClassObject * type,s4 * destPtr)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  */
dvmBoxPrimitive(JValue value,ClassObject * returnType)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  */
dvmUnboxPrimitive(Object * value,ClassObject * returnType,JValue * pResult)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  */
dvmGetBoxedReturnType(const Method * meth)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  */
dvmGetFieldFromReflectObj(Object * obj)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  */
dvmGetMethodFromReflectObj(Object * obj)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  */
dvmCreateReflectObjForField(const ClassObject * clazz,Field * field)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  */
dvmCreateReflectObjForMethod(const ClassObject * clazz,Method * method)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