OSDN Git Service

Test and fix for the ArrayList.addAll(), bug 2954.
[android-x86/dalvik.git] / vm / Native.c
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  * Native method resolution.
18  *
19  * Currently the "Dalvik native" methods are only used for internal methods.
20  * Someday we may want to export the interface as a faster but riskier
21  * alternative to JNI.
22  */
23 #include "Dalvik.h"
24
25 #include <stdlib.h>
26 #include <dlfcn.h>
27
28 static void freeSharedLibEntry(void* ptr);
29 static void* lookupSharedLibMethod(const Method* method);
30
31
32 /*
33  * Initialize the native code loader.
34  */
35 bool dvmNativeStartup(void)
36 {
37     gDvm.nativeLibs = dvmHashTableCreate(4, freeSharedLibEntry);
38     if (gDvm.nativeLibs == NULL)
39         return false;
40
41     return true;
42 }
43
44 /*
45  * Free up our tables.
46  */
47 void dvmNativeShutdown(void)
48 {
49     dvmHashTableFree(gDvm.nativeLibs);
50     gDvm.nativeLibs = NULL;
51 }
52
53
54 /*
55  * Resolve a native method and invoke it.
56  *
57  * This is executed as if it were a native bridge or function.  If the
58  * resolution succeeds, method->insns is replaced, and we don't go through
59  * here again.
60  *
61  * Initializes method's class if necessary.
62  *
63  * An exception is thrown on resolution failure.
64  */
65 void dvmResolveNativeMethod(const u4* args, JValue* pResult,
66     const Method* method, Thread* self)
67 {
68     ClassObject* clazz = method->clazz;
69     void* func;
70
71     /*
72      * If this is a static method, it could be called before the class
73      * has been initialized.
74      */
75     if (dvmIsStaticMethod(method)) {
76         if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
77             assert(dvmCheckException(dvmThreadSelf()));
78             return;
79         }
80     } else {
81         assert(dvmIsClassInitialized(clazz) ||
82                dvmIsClassInitializing(clazz));
83     }
84
85     /* start with our internal-native methods */
86     func = dvmLookupInternalNativeMethod(method);
87     if (func != NULL) {
88         /* resolution always gets the same answer, so no race here */
89         IF_LOGVV() {
90             char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
91             LOGVV("+++ resolved native %s.%s %s, invoking\n",
92                 clazz->descriptor, method->name, desc);
93             free(desc);
94         }
95         if (dvmIsSynchronizedMethod(method)) {
96             LOGE("ERROR: internal-native can't be declared 'synchronized'\n");
97             LOGE("Failing on %s.%s\n", method->clazz->descriptor, method->name);
98             dvmAbort();     // harsh, but this is VM-internal problem
99         }
100         DalvikBridgeFunc dfunc = (DalvikBridgeFunc) func;
101         dvmSetNativeFunc(method, dfunc, NULL);
102         assert(method->insns == NULL);
103         dfunc(args, pResult, method, self);
104         return;
105     }
106
107     /* now scan any DLLs we have loaded for JNI signatures */
108     func = lookupSharedLibMethod(method);
109     if (func != NULL) {
110         if (dvmIsSynchronizedMethod(method))
111             dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, func);
112         else
113             dvmSetNativeFunc(method, dvmCallJNIMethod, func);
114         dvmCallJNIMethod(args, pResult, method, self);
115         return;
116     }
117
118     IF_LOGW() {
119         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
120         LOGW("No implementation found for native %s.%s %s\n",
121             clazz->descriptor, method->name, desc);
122         free(desc);
123     }
124
125     dvmThrowException("Ljava/lang/UnsatisfiedLinkError;", method->name);
126 }
127
128
129 /*
130  * ===========================================================================
131  *      Native shared library support
132  * ===========================================================================
133  */
134
135 // TODO? if a ClassLoader is unloaded, we need to unload all DLLs that
136 // are associated with it.  (Or not -- can't determine if native code
137 // is still using parts of it.)
138
139 /*
140  * We add one of these to the hash table for every library we load.  The
141  * hash is on the "pathName" field.
142  */
143 typedef struct SharedLib {
144     char*       pathName;       /* absolute path to library */
145     void*       handle;         /* from dlopen */
146     Object*     classLoader;    /* ClassLoader we are associated with */
147 } SharedLib;
148
149 /*
150  * (This is a dvmHashTableLookup callback.)
151  *
152  * Find an entry that matches the string.
153  */
154 static int hashcmpNameStr(const void* ventry, const void* vname)
155 {
156     const SharedLib* pLib = (const SharedLib*) ventry;
157     const char* name = (const char*) vname;
158
159     return strcmp(pLib->pathName, name);
160 }
161
162 /*
163  * (This is a dvmHashTableLookup callback.)
164  *
165  * Find an entry that matches the new entry.
166  */
167 static int hashcmpSharedLib(const void* ventry, const void* vnewEntry)
168 {
169     const SharedLib* pLib = (const SharedLib*) ventry;
170     const SharedLib* pNewLib = (const SharedLib*) vnewEntry;
171
172     LOGD("--- comparing %p '%s' %p '%s'\n",
173         pLib, pLib->pathName, pNewLib, pNewLib->pathName);
174     return strcmp(pLib->pathName, pNewLib->pathName);
175 }
176
177 /*
178  * Check to see if an entry with the same pathname already exists.
179  */
180 static const SharedLib* findSharedLibEntry(const char* pathName)
181 {
182     u4 hash = dvmComputeUtf8Hash(pathName);
183     void* ent;
184
185     ent = dvmHashTableLookup(gDvm.nativeLibs, hash, (void*)pathName,
186                 hashcmpNameStr, false);
187     return ent;
188 }
189
190 /*
191  * Add the new entry to the table.
192  *
193  * Returns "true" on success, "false" if the entry already exists.
194  */
195 static bool addSharedLibEntry(SharedLib* pLib)
196 {
197     u4 hash = dvmComputeUtf8Hash(pLib->pathName);
198     void* ent;
199
200     /*
201      * Do the lookup with the "add" flag set.  If we add it, we will get
202      * our own pointer back.  If somebody beat us to the punch, we'll get
203      * their pointer back instead.
204      */
205     ent = dvmHashTableLookup(gDvm.nativeLibs, hash, pLib, hashcmpSharedLib,
206                 true);
207     return (ent == pLib);
208 }
209
210 /*
211  * Free up an entry.  (This is a dvmHashTableFree callback.)
212  */
213 static void freeSharedLibEntry(void* ptr)
214 {
215     SharedLib* pLib = (SharedLib*) ptr;
216
217     /*
218      * Calling dlclose() here is somewhat dangerous, because it's possible
219      * that a thread outside the VM is still accessing the code we loaded.
220      */
221     if (false)
222         dlclose(pLib->handle);
223     free(pLib->pathName);
224     free(pLib);
225 }
226
227 /*
228  * Convert library name to system-dependent form, e.g. "jpeg" becomes
229  * "libjpeg.so".
230  *
231  * (Should we have this take buffer+len and avoid the alloc?  It gets
232  * called very rarely.)
233  */
234 char* dvmCreateSystemLibraryName(char* libName)
235 {
236     char buf[256];
237     int len;
238
239     len = snprintf(buf, sizeof(buf), OS_SHARED_LIB_FORMAT_STR, libName);
240     if (len >= (int) sizeof(buf))
241         return NULL;
242     else
243         return strdup(buf);
244 }
245
246
247 #if 0
248 /*
249  * Find a library, given the lib's system-dependent name (e.g. "libjpeg.so").
250  *
251  * We need to search through the path defined by the java.library.path
252  * property.
253  *
254  * Returns NULL if the library was not found.
255  */
256 static char* findLibrary(const char* libSysName)
257 {
258     char* javaLibraryPath = NULL;
259     char* testName = NULL;
260     char* start;
261     char* cp;
262     bool done;
263
264     javaLibraryPath = dvmGetProperty("java.library.path");
265     if (javaLibraryPath == NULL)
266         goto bail;
267
268     LOGVV("+++ path is '%s'\n", javaLibraryPath);
269
270     start = cp = javaLibraryPath;
271     while (cp != NULL) {
272         char pathBuf[256];
273         int len;
274
275         cp = strchr(start, ':');
276         if (cp != NULL)
277             *cp = '\0';
278
279         len = snprintf(pathBuf, sizeof(pathBuf), "%s/%s", start, libSysName);
280         if (len >= (int) sizeof(pathBuf)) {
281             LOGW("Path overflowed %d bytes: '%s' / '%s'\n",
282                 len, start, libSysName);
283             /* keep going, next one might fit */
284         } else {
285             LOGVV("+++  trying '%s'\n", pathBuf);
286             if (access(pathBuf, R_OK) == 0) {
287                 testName = strdup(pathBuf);
288                 break;
289             }
290         }
291
292         start = cp +1;
293     }
294
295 bail:
296     free(javaLibraryPath);
297     return testName;
298 }
299
300 /*
301  * Load a native shared library, given the system-independent piece of
302  * the library name.
303  *
304  * Throws an exception on failure.
305  */
306 void dvmLoadNativeLibrary(StringObject* libNameObj, Object* classLoader)
307 {
308     char* libName = NULL;
309     char* libSysName = NULL;
310     char* libPath = NULL;
311
312     /*
313      * If "classLoader" isn't NULL, call the class loader's "findLibrary"
314      * method with the lib name.  If it returns a non-NULL result, we use
315      * that as the pathname.
316      */
317     if (classLoader != NULL) {
318         Method* findLibrary;
319         Object* findLibResult;
320
321         findLibrary = dvmFindVirtualMethodByDescriptor(classLoader->clazz,
322             "findLibrary", "(Ljava/lang/String;)Ljava/lang/String;");
323         if (findLibrary == NULL) {
324             LOGW("Could not find findLibrary() in %s\n",
325                 classLoader->clazz->name);
326             dvmThrowException("Ljava/lang/UnsatisfiedLinkError;",
327                 "findLibrary");
328             goto bail;
329         }
330
331         findLibResult = (Object*)(u4) dvmCallMethod(findLibrary, classLoader,
332                                             libNameObj);
333         if (dvmCheckException()) {
334             LOGV("returning early on exception\n");
335             goto bail;
336         }
337         if (findLibResult != NULL) {
338             /* success! */
339             libPath = dvmCreateCstrFromString(libNameObj);
340             LOGI("Found library through CL: '%s'\n", libPath);
341             dvmLoadNativeCode(libPath, classLoader);
342             goto bail;
343         }
344     }
345
346     libName = dvmCreateCstrFromString(libNameObj);
347     if (libName == NULL)
348         goto bail;
349     libSysName = dvmCreateSystemLibraryName(libName);
350     if (libSysName == NULL)
351         goto bail;
352
353     libPath = findLibrary(libSysName);
354     if (libPath != NULL) {
355         LOGD("Found library through path: '%s'\n", libPath);
356         dvmLoadNativeCode(libPath, classLoader);
357     } else {
358         LOGW("Unable to locate shared lib matching '%s'\n", libSysName);
359         dvmThrowException("Ljava/lang/UnsatisfiedLinkError;", libName);
360     }
361
362 bail:
363     free(libName);
364     free(libSysName);
365     free(libPath);
366 }
367 #endif
368
369 typedef int (*OnLoadFunc)(JavaVM*, void*);
370
371 /*
372  * Load native code from the specified absolute pathname.  Per the spec,
373  * if we've already loaded a library with the specified pathname, we
374  * return without doing anything.
375  *
376  * TODO? for better results we should absolutify the pathname.  For fully
377  * correct results we should stat to get the inode and compare that.  The
378  * existing implementation is fine so long as everybody is using
379  * System.loadLibrary.
380  *
381  * The library will be associated with the specified class loader.  The JNI
382  * spec says we can't load the same library into more than one class loader.
383  *
384  * Returns "true" on success.
385  */
386 bool dvmLoadNativeCode(const char* pathName, Object* classLoader)
387 {
388     const SharedLib* pEntry;
389     void* handle;
390
391     LOGD("Trying to load lib %s %p\n", pathName, classLoader);
392
393     /*
394      * See if we've already loaded it.  If we have, and the class loader
395      * matches, return successfully without doing anything.
396      */
397     pEntry = findSharedLibEntry(pathName);
398     if (pEntry != NULL) {
399         if (pEntry->classLoader != classLoader) {
400             LOGW("Shared lib '%s' already opened by CL %p; can't open in %p\n",
401                 pathName, pEntry->classLoader, classLoader);
402             return false;
403         }
404         LOGD("Shared lib '%s' already loaded in same CL %p\n",
405             pathName, classLoader);
406         return true;
407     }
408
409     /*
410      * Open the shared library.  Because we're using a full path, the system
411      * doesn't have to search through LD_LIBRARY_PATH.  (It may do so to
412      * resolve this library's dependencies though.)
413      *
414      * Failures here are expected when java.library.path has several entries.
415      *
416      * The current android-arm dynamic linker implementation tends to
417      * return "Cannot find library" from dlerror() regardless of the actual
418      * problem.  A more useful diagnostic may be sent to stdout/stderr,
419      * but often that's not visible.  Some things to try:
420      *   - make sure the library exists on the device
421      *   - verify that the right path is being opened (the debug log message
422      *     above can help with that)
423      *   - check to see if the library is valid
424      *   - check config/prelink-linux-arm.map to ensure that the library
425      *     is listed and is not being overrun by the previous entry (if
426      *     loading suddenly stops working, this is a good one to check)
427      */
428     handle = dlopen(pathName, RTLD_LAZY);
429     if (handle == NULL) {
430         LOGI("Unable to dlopen(%s): %s\n", pathName, dlerror());
431         return false;
432     }
433
434     SharedLib* pNewEntry;
435     pNewEntry = (SharedLib*) malloc(sizeof(SharedLib));
436     pNewEntry->pathName = strdup(pathName);
437     pNewEntry->handle = handle;
438     pNewEntry->classLoader = classLoader;
439     if (!addSharedLibEntry(pNewEntry)) {
440         LOGI("WOW: we lost a race to add a shared lib (%s %p)\n",
441             pathName, classLoader);
442         /* free up our entry, and just return happy that one exists */
443         freeSharedLibEntry(pNewEntry);
444     } else {
445         LOGD("Added shared lib %s %p\n", pathName, classLoader);
446
447         void* vonLoad;
448         int version;
449
450         vonLoad = dlsym(handle, "JNI_OnLoad");
451         if (vonLoad == NULL) {
452             LOGD("No JNI_OnLoad found in %s %p\n", pathName, classLoader);
453         } else {
454             /*
455              * Call JNI_OnLoad.  We have to override the current class
456              * loader, which will always be "null" since the stuff at the
457              * top of the stack is around Runtime.loadLibrary().
458              */
459             OnLoadFunc func = vonLoad;
460             Thread* self = dvmThreadSelf();
461             Object* prevOverride = self->classLoaderOverride;
462
463             self->classLoaderOverride = classLoader;
464             dvmChangeStatus(NULL, THREAD_NATIVE);
465             version = (*func)(gDvm.vmList, NULL);
466             dvmChangeStatus(NULL, THREAD_RUNNING);
467             self->classLoaderOverride = prevOverride;
468
469             if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&
470                 version != JNI_VERSION_1_6)
471             {
472                 LOGW("JNI_OnLoad returned bad version (%d) in %s %p\n",
473                     version, pathName, classLoader);
474                 // TODO: dlclose, remove hash table entry
475                 return false;
476             }
477         }
478     }
479
480     return true;
481 }
482
483
484 /*
485  * ===========================================================================
486  *      Signature-based method lookup
487  * ===========================================================================
488  */
489
490 /*
491  * Create the pre-mangled form of the class+method string.
492  *
493  * Returns a newly-allocated string, and sets "*pLen" to the length.
494  */
495 static char* createJniNameString(const char* classDescriptor,
496     const char* methodName, int* pLen)
497 {
498     char* result;
499     size_t descriptorLength = strlen(classDescriptor);
500
501     *pLen = 4 + descriptorLength + strlen(methodName);
502
503     result = malloc(*pLen +1);
504     if (result == NULL)
505         return NULL;
506
507     /*
508      * Add one to classDescriptor to skip the "L", and then replace
509      * the final ";" with a "/" after the sprintf() call.
510      */
511     sprintf(result, "Java/%s%s", classDescriptor + 1, methodName);
512     result[5 + (descriptorLength - 2)] = '/';
513
514     return result;
515 }
516
517 /*
518  * Returns a newly-allocated, mangled copy of "str".
519  *
520  * "str" is a "modified UTF-8" string.  We convert it to UTF-16 first to
521  * make life simpler.
522  */
523 static char* mangleString(const char* str, int len)
524 {
525     u2* utf16 = NULL;
526     char* mangle = NULL;
527     int charLen;
528
529     //LOGI("mangling '%s' %d\n", str, len);
530
531     assert(str[len] == '\0');
532
533     charLen = dvmUtf8Len(str);
534     utf16 = (u2*) malloc(sizeof(u2) * charLen);
535     if (utf16 == NULL)
536         goto bail;
537
538     dvmConvertUtf8ToUtf16(utf16, str);
539
540     /*
541      * Compute the length of the mangled string.
542      */
543     int i, mangleLen = 0;
544
545     for (i = 0; i < charLen; i++) {
546         u2 ch = utf16[i];
547
548         if (ch > 127) {
549             mangleLen += 6;
550         } else {
551             switch (ch) {
552             case '_':
553             case ';':
554             case '[':
555                 mangleLen += 2;
556                 break;
557             default:
558                 mangleLen++;
559                 break;
560             }
561         }
562     }
563
564     char* cp;
565
566     mangle = (char*) malloc(mangleLen +1);
567     if (mangle == NULL)
568         goto bail;
569
570     for (i = 0, cp = mangle; i < charLen; i++) {
571         u2 ch = utf16[i];
572
573         if (ch > 127) {
574             sprintf(cp, "_0%04x", ch);
575             cp += 6;
576         } else {
577             switch (ch) {
578             case '_':
579                 *cp++ = '_';
580                 *cp++ = '1';
581                 break;
582             case ';':
583                 *cp++ = '_';
584                 *cp++ = '2';
585                 break;
586             case '[':
587                 *cp++ = '_';
588                 *cp++ = '3';
589                 break;
590             case '/':
591                 *cp++ = '_';
592                 break;
593             default:
594                 *cp++ = (char) ch;
595                 break;
596             }
597         }
598     }
599
600     *cp = '\0';
601
602 bail:
603     free(utf16);
604     return mangle;
605 }
606
607 /*
608  * Create the mangled form of the parameter types.
609  */
610 static char* createMangledSignature(const DexProto* proto)
611 {
612     DexStringCache sigCache;
613     const char* interim;
614     char* result;
615
616     dexStringCacheInit(&sigCache);
617     interim = dexProtoGetParameterDescriptors(proto, &sigCache);
618     result = mangleString(interim, strlen(interim));
619     dexStringCacheRelease(&sigCache);
620
621     return result;
622 }
623
624 /*
625  * (This is a dvmHashForeach callback.)
626  *
627  * Search for a matching method in this shared library.
628  */
629 static int findMethodInLib(void* vlib, void* vmethod)
630 {
631     const SharedLib* pLib = (const SharedLib*) vlib;
632     const Method* meth = (const Method*) vmethod;
633     char* preMangleCM = NULL;
634     char* mangleCM = NULL;
635     char* mangleSig = NULL;
636     char* mangleCMSig = NULL;
637     void* func = NULL;
638     int len;
639
640     if (meth->clazz->classLoader != pLib->classLoader) {
641         LOGD("+++ not scanning '%s' for '%s' (wrong CL)\n",
642             pLib->pathName, meth->name);
643         return 0;
644     } else
645         LOGV("+++ scanning '%s' for '%s'\n", pLib->pathName, meth->name);
646
647     /*
648      * First, we try it without the signature.
649      */
650     preMangleCM =
651         createJniNameString(meth->clazz->descriptor, meth->name, &len);
652     if (preMangleCM == NULL)
653         goto bail;
654
655     mangleCM = mangleString(preMangleCM, len);
656     if (mangleCM == NULL)
657         goto bail;
658
659     LOGV("+++ calling dlsym(%s)\n", mangleCM);
660     func = dlsym(pLib->handle, mangleCM);
661     if (func == NULL) {
662         mangleSig =
663             createMangledSignature(&meth->prototype);
664         if (mangleSig == NULL)
665             goto bail;
666
667         mangleCMSig = (char*) malloc(strlen(mangleCM) + strlen(mangleSig) +3);
668         if (mangleCMSig == NULL)
669             goto bail;
670
671         sprintf(mangleCMSig, "%s__%s", mangleCM, mangleSig);
672
673         LOGV("+++ calling dlsym(%s)\n", mangleCMSig);
674         func = dlsym(pLib->handle, mangleCMSig);
675         if (func != NULL) {
676             LOGV("Found '%s' with dlsym\n", mangleCMSig);
677         }
678     } else {
679         LOGV("Found '%s' with dlsym\n", mangleCM);
680     }
681
682 bail:
683     free(preMangleCM);
684     free(mangleCM);
685     free(mangleSig);
686     free(mangleCMSig);
687     return (int) func;
688 }
689
690 /*
691  * See if the requested method lives in any of the currently-loaded
692  * shared libraries.  We do this by checking each of them for the expected
693  * method signature.
694  */
695 static void* lookupSharedLibMethod(const Method* method)
696 {
697     if (gDvm.nativeLibs == NULL) {
698         LOGE("Unexpected init state: nativeLibs not ready\n");
699         dvmAbort();
700     }
701     return (void*) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,
702         (void*) method);
703 }
704