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