java system load_Java中System.loadLibrary() 的执行过程

该博客详细描述了如何从指定绝对路径加载native代码,避免重复加载,并确保正确关联到指定的类加载器。重点在于处理JNI_OnLoad函数,验证库版本和错误处理。遇到问题时提供了排查建议,如检查库存在性、路径正确性和依赖关系等。
摘要由CSDN通过智能技术生成

/*

* Load native code from the specified absolute pathname.  Per the spec,

* if we've already loaded a library with the specified pathname, we

* return without doing anything.

*

* TODO? for better results we should absolutify the pathname.  For fully

* correct results we should stat to get the inode and compare that.  The

* existing implementation is fine so long as everybody is using

* System.loadLibrary.

*

* The library will be associated with the specified class loader.  The JNI

* spec says we can't load the same library into more than one class loader.

*

* Returns "true" on success. On failure, sets *detail to a

* human-readable description of the error or NULL if no detail is

* available; ownership of the string is transferred to the caller.

*/

booldvmLoadNativeCode(constchar* pathName, Object* classLoader,

char** detail)

{

SharedLib* pEntry;

void* handle;

boolverbose;

/* reduce noise by not chattering about system libraries */

verbose = !!strncmp(pathName,"/system",sizeof("/system")-1);

verbose = verbose && !!strncmp(pathName,"/vendor",sizeof("/vendor")-1);

if(verbose)

ALOGD("Trying to load lib %s %p", pathName, classLoader);

*detail = NULL;

/*

* See if we've already loaded it.  If we have, and the class loader

* matches, return successfully without doing anything.

*/

pEntry = findSharedLibEntry(pathName);

if(pEntry != NULL) {

if(pEntry->classLoader != classLoader) {

ALOGW("Shared lib '%s' already opened by CL %p; can't open in %p",

pathName, pEntry->classLoader, classLoader);

returnfalse;

}

if(verbose) {

ALOGD("Shared lib '%s' already loaded in same CL %p",

pathName, classLoader);

}

if(!checkOnLoadResult(pEntry))

returnfalse;

returntrue;

}

/*

* Open the shared library.  Because we're using a full path, the system

* doesn't have to search through LD_LIBRARY_PATH.  (It may do so to

* resolve this library's dependencies though.)

*

* Failures here are expected when java.library.path has several entries

* and we have to hunt for the lib.

*

* The current version of the dynamic linker prints detailed information

* about dlopen() failures.  Some things to check if the message is

* cryptic:

*   - make sure the library exists on the device

*   - verify that the right path is being opened (the debug log message

*     above can help with that)

*   - check to see if the library is valid (e.g. not zero bytes long)

*   - check config/prelink-linux-arm.map to ensure that the library

*     is listed and is not being overrun by the previous entry (if

*     loading suddenly stops working on a prelinked library, this is

*     a good one to check)

*   - write a trivial app that calls sleep() then dlopen(), attach

*     to it with "strace -p " while it sleeps, and watch for

*     attempts to open nonexistent dependent shared libs

*

* This can execute slowly for a large library on a busy system, so we

* want to switch from RUNNING to VMWAIT while it executes.  This allows

* the GC to ignore us.

*/

Thread* self = dvmThreadSelf();

ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);

handle = dlopen(pathName, RTLD_LAZY);

dvmChangeStatus(self, oldStatus);

if(handle == NULL) {

*detail = strdup(dlerror());

ALOGE("dlopen(\"%s\") failed: %s", pathName, *detail);

returnfalse;

}

/* create a new entry */

SharedLib* pNewEntry;

pNewEntry = (SharedLib*)calloc(1,sizeof(SharedLib));

pNewEntry->pathName = strdup(pathName);

pNewEntry->handle = handle;

pNewEntry->classLoader = classLoader;

dvmInitMutex(&pNewEntry->onLoadLock);

pthread_cond_init(&pNewEntry->onLoadCond, NULL);

pNewEntry->onLoadThreadId = self->threadId;

/* try to add it to the list */

SharedLib* pActualEntry = addSharedLibEntry(pNewEntry);

if(pNewEntry != pActualEntry) {

ALOGI("WOW: we lost a race to add a shared lib (%s CL=%p)",

pathName, classLoader);

freeSharedLibEntry(pNewEntry);

returncheckOnLoadResult(pActualEntry);

}else{

if(verbose)

ALOGD("Added shared lib %s %p", pathName, classLoader);

boolresult =true;

void* vonLoad;

intversion;

vonLoad = dlsym(handle,"JNI_OnLoad");

if(vonLoad == NULL) {

ALOGD("No JNI_OnLoad found in %s %p, skipping init",

pathName, classLoader);

}else{

/*

* Call JNI_OnLoad.  We have to override the current class

* loader, which will always be "null" since the stuff at the

* top of the stack is around Runtime.loadLibrary().  (See

* the comments in the JNI FindClass function.)

*/

OnLoadFunc func = (OnLoadFunc)vonLoad;

Object* prevOverride = self->classLoaderOverride;

self->classLoaderOverride = classLoader;

oldStatus = dvmChangeStatus(self, THREAD_NATIVE);

if(gDvm.verboseJni) {

ALOGI("[Calling JNI_OnLoad for \"%s\"]", pathName);

}

version = (*func)(gDvmJni.jniVm, NULL);

dvmChangeStatus(self, oldStatus);

self->classLoaderOverride = prevOverride;

if(version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&

version != JNI_VERSION_1_6)

{

ALOGW("JNI_OnLoad returned bad version (%d) in %s %p",

version, pathName, classLoader);

/*

* It's unwise to call dlclose() here, but we can mark it

* as bad and ensure that future load attempts will fail.

*

* We don't know how far JNI_OnLoad got, so there could

* be some partially-initialized stuff accessible through

* newly-registered native method calls.  We could try to

* unregister them, but that doesn't seem worthwhile.

*/

result =false;

}else{

if(gDvm.verboseJni) {

ALOGI("[Returned from JNI_OnLoad for \"%s\"]", pathName);

}

}

}

if(result)

pNewEntry->onLoadResult = kOnLoadOkay;

else

pNewEntry->onLoadResult = kOnLoadFailed;

pNewEntry->onLoadThreadId = 0;

/*

* Broadcast a wakeup to anybody sleeping on the condition variable.

*/

dvmLockMutex(&pNewEntry->onLoadLock);

pthread_cond_broadcast(&pNewEntry->onLoadCond);

dvmUnlockMutex(&pNewEntry->onLoadLock);

returnresult;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值