安卓手机如何打开 so文件(Android中怎么加载so文件源码)

发布时间:2025-12-11 03:20:38 浏览次数:9

要使用ndk进行编程,在Java层就必须要对so进行加载。Java层加载so的函数有两个:

System.load(StringpathName)System.loadLibraray(StringlibName)

两个函数的区别就是load函数的参数是so文件的绝对地址。loadLibrary的参数是so的名称,这个so文件必须放在apk的lib目录下,而且so的名称必须去掉前面的lib和后边的“.so”。如下所示:

System.load("/data/local/tmp/libhello.so");System.loadLibrary("hello");

System.java

load和loadLibraray函数在/android6.0/libcore/luni/src/main/java/java/lang/System.java中:

publicstaticvoidload(StringpathName){Runtime.getRuntime().load(pathName,VMStack.getCallingClassLoader());}/***See{@linkRuntime#loadLibrary}.*/publicstaticvoidloadLibrary(StringlibName){Runtime.getRuntime().loadLibrary(libName,VMStack.getCallingClassLoader());}

Runtime.java

getRuntime()函数用于获取Runtime的一个实例。

publicstaticRuntimegetRuntime(){returnmRuntime;}

loadLibrary():

publicvoidloadLibrary(Stringnickname){loadLibrary(nickname,VMStack.getCallingClassLoader());}voidloadLibrary(StringlibraryName,ClassLoaderloader){if(loader!=null){Stringfilename=loader.findLibrary(libraryName);if(filename==null){//It'snotnecessarilytruethattheClassLoaderused//System.mapLibraryName,butthedefaultsetupdoes,andit's//misleadingtosaywedidn'tfind"libMyLibrary.so"whenwe//actuallysearchedfor"liblibMyLibrary.so.so".thrownewUnsatisfiedLinkError(loader+"couldn'tfind\""+System.mapLibraryName(libraryName)+"\"");}Stringerror=doLoad(filename,loader);if(error!=null){thrownewUnsatisfiedLinkError(error);}return;}Stringfilename=System.mapLibraryName(libraryName);List<String>candidates=newArrayList<String>();StringlastError=null;for(Stringdirectory:mLibPaths){Stringcandidate=directory+filename;candidates.add(candidate);if(IoUtils.canOpenReadOnly(candidate)){Stringerror=doLoad(candidate,loader);if(error==null){return;//Wesuccessfullyloadedthelibrary.Jobdone.}lastError=error;}}if(lastError!=null){thrownewUnsatisfiedLinkError(lastError);}thrownewUnsatisfiedLinkError("Library"+libraryName+"notfound;tried"+candidates);}

loadLibrary()函数主要进行了两步操作。

第一步:获取library的path:

根据ClassLoader的不同,会有两种不同的处理方法。

如果ClassLoader非空,会利用ClassLoader的findLibrary()方法获取library的path。

如果ClassLoader为空,会通过传入的library name和System.mapLibraryName获得真正的library name。例如传入的是hello,

得到的是libhello.so,然后在mLibPaths查找`libhello.so',最终确定library的path。

第二步:调用doLoad()方法。

第一步目前我不关心,不去深究。主要看doLoad的实现。

privateStringdoLoad(Stringname,ClassLoaderloader){StringldLibraryPath=null;StringdexPath=null;if(loader==null){//Weusethegivenlibrarypathforthebootclassloader.Thisisthepath//alsousedinloadLibraryNameifloaderisnull.ldLibraryPath=System.getProperty("java.library.path");}elseif(loaderinstanceofBaseDexClassLoader){BaseDexClassLoaderdexClassLoader=(BaseDexClassLoader)loader;ldLibraryPath=dexClassLoader.getLdLibraryPath();}//nativeLoadshouldbesynchronizedsothere'sonlyoneLD_LIBRARY_PATHinuseregardless//ofhowmanyClassLoadersareinthesystem,butdalvikdoesn'tsupportsynchronized//internalnatives.synchronized(this){returnnativeLoad(name,loader,ldLibraryPath);}}

获得libbrary的路径;

调用native函数nativeLoad()进行加载加载。

java_lang_Runtime.cc

文件位置:/android6.0.1_r66/art/runtime/native/java_lang_Runtime.cc

staticjstringRuntime_nativeLoad(JNIEnv*env,jclass,jstringjavaFilename,jobjectjavaLoader,jstringjavaLdLibraryPathJstr){ScopedUtfCharsfilename(env,javaFilename);if(filename.c_str()==nullptr){returnnullptr;}SetLdLibraryPath(env,javaLdLibraryPathJstr);std::stringerror_msg;{JavaVMExt*vm=Runtime::Current()->GetJavaVM();boolsuccess=vm->LoadNativeLibrary(env,filename.c_str(),javaLoader,&error_msg);if(success){returnnullptr;}}//Don'tletapendingexceptionfromJNI_OnLoadcauseaCheckJNIissuewithNewStringUTF.env->ExceptionClear();returnenv->NewStringUTF(error_msg.c_str());}

nativeLoad()主要做了两件事:

第一件事:利用SetLdLibraryPath()将Java的library的path转换成native的。

第二件事情:调用LoadNativeLibrary进行加载。<关键>

java_vm_ext.cc

位置:/android6.0/art/runtime/java_vm_ext.cc

boolJavaVMExt::LoadNativeLibrary(JNIEnv*env,conststd::string&path,jobjectclass_loader,std::string*error_msg){...constchar*path_str=path.empty()?nullptr:path.c_str();void*handle=dlopen(path_str,RTLD_NOW);...if(needs_native_bridge){library->SetNeedsNativeBridge();sym=library->FindSymbolWithNativeBridge("JNI_OnLoad",nullptr);}else{sym=dlsym(handle,"JNI_OnLoad");}if(sym==nullptr){VLOG(jni)<<"[NoJNI_OnLoadfoundin\""<<path<<"\"]";was_successful=true;}else{

利用dlopen()打开so文件,得到函数的指针

利用dlsym()调用so文件中的JNI_OnLoad方法,开始so文件的执行。

关于Android中怎么加载so文件源码问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注本站行业资讯频道了解更多相关知识。

安卓手机如何打开 so文件
需要做网站?需要网络推广?欢迎咨询客户经理 13272073477