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