要使用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文件源碼問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注本站行業資訊頻道了解更多相關知識。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
鞍鋼與攀鋼的關系是怎么樣的?攀鋼集團有限公司是鞍鋼集團公司的全資子公司。攀鋼依托攀西地區豐富的釩鈦磁鐵礦資源優勢,依靠自主創新推動鋼鐵釩鈦產業跨越式發展,通過一期、二期工程建設及近年來的技術改造和資本運營,已發展成為跨地區、跨行業的現代化鋼鐵釩鈦企業集團。鋼鐵釩鈦主業主要分布在四川省攀枝花市、成都市青白江區、綿陽市江油市及重慶市、廣西自治區北海市。經營性資產已實現整體上市。攀鋼為什么和鞍鋼合并?1...
廣州電信dns地址多少?廣州dns首選和備用填多少?廣東省廣州市(中國電信)首選DNS:202.96.128.86 備份DNS:202.96.128.166廣東省汕尾市(中國電信)首選DNS:202.96.128.166 備份DNS:202.96.128.86廣東省汕頭市(中國電信)備份DNS:202.96.128.166廣東省河源市(中國電信)首選DNS:202.96.128.166 備份DNS...
(資料圖片)在生活中,很多人都不知道無錫有哪些歷史名人是什么意思,其實他的意思是非常簡單的,下面就是小編搜索到的無錫有哪些歷史名人相關的一些知識,我們一起來學習下吧!無錫有以下歷史名人:1、顧憲成:明代思想家,東林黨領袖。2、泰伯:吳國第一代君主,東吳文化的宗祖。3、仲雍:吳國第二代君主,吳地和常熟的始祖。3、季簡:周代吳國的第三任君主。4、叔達:西周時期吳國第四任國君。5、周章:秦末農民起義軍將...