最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入分析Android加載so文件源碼

 更新時(shí)間:2018年03月21日 11:29:35   作者:wydong  
這篇文章主要介紹了深入分析Android加載so文件源碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

Android系統(tǒng)中使用ndk進(jìn)行編程,有很多的好處(Java的跨平臺(tái)特性導(dǎo)致其本地交互的能力不夠強(qiáng)大,一些和操作系統(tǒng)相關(guān)的特性Java無法完成;代碼的保護(hù):由于apk的java層代碼很容易被反編譯,而C/C++庫(kù)反匯難度較大;可以方便地使用C/C++開源庫(kù);便于移植,用C/C++寫的庫(kù)可以方便在其他平臺(tái)上再次使用;提供程序在某些特定情形下的執(zhí)行效率,但是并不能明顯提升Android程序的性能)。

要使用ndk進(jìn)行編程,在Java層就必須要對(duì)so進(jìn)行加載。Java層加載so的函數(shù)有兩個(gè):

System.load(String pathName)
System.loadLibraray(String libName)

兩個(gè)函數(shù)的區(qū)別就是load函數(shù)的參數(shù)是so文件的絕對(duì)地址。loadLibrary的參數(shù)是so的名稱,這個(gè)so文件必須放在apk的lib目錄下,而且so的名稱必須去掉前面的lib和后邊的“.so”。如下所示:

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

System.java

load和loadLibraray函數(shù)在/android6.0/libcore/luni/src/main/java/java/lang/System.java中:

public static void load(String pathName) {
    Runtime.getRuntime().load(pathName, VMStack.getCallingClassLoader());
  }

  /**
   * See {@link Runtime#loadLibrary}.
   */
  public static void loadLibrary(String libName) {
    Runtime.getRuntime().loadLibrary(libName, VMStack.getCallingClassLoader());
  }

Runtime.java

getRuntime()函數(shù)用于獲取Runtime的一個(gè)實(shí)例。

 public static Runtime getRuntime() {
    return mRuntime;
  }

loadLibrary():

public void loadLibrary(String nickname) {
    loadLibrary(nickname, VMStack.getCallingClassLoader());
  }
  
   void loadLibrary(String libraryName, ClassLoader loader) {
    if (loader != null) {
      String filename = loader.findLibrary(libraryName);
      if (filename == null) {
        // It's not necessarily true that the ClassLoader used
        // System.mapLibraryName, but the default setup does, and it's
        // misleading to say we didn't find "libMyLibrary.so" when we
        // actually searched for "liblibMyLibrary.so.so".
        throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
                        System.mapLibraryName(libraryName) + "\"");
      }
      String error = doLoad(filename, loader);
      if (error != null) {
        throw new UnsatisfiedLinkError(error);
      }
      return;
    }

    String filename = System.mapLibraryName(libraryName);
    List<String> candidates = new ArrayList<String>();
    String lastError = null;
    for (String directory : mLibPaths) {
      String candidate = directory + filename;
      candidates.add(candidate);

      if (IoUtils.canOpenReadOnly(candidate)) {
        String error = doLoad(candidate, loader);
        if (error == null) {
          return; // We successfully loaded the library. Job done.
        }
        lastError = error;
      }
    }

    if (lastError != null) {
      throw new UnsatisfiedLinkError(lastError);
    }
    throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}

loadLibrary()函數(shù)主要進(jìn)行了兩步操作。

第一步:獲取library的path:

根據(jù)ClassLoader的不同,會(huì)有兩種不同的處理方法。

如果ClassLoader非空,會(huì)利用ClassLoader的findLibrary()方法獲取library的path。

如果ClassLoader為空,會(huì)通過傳入的library name和System.mapLibraryName獲得真正的library name。例如傳入的是hello,

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

第二步:調(diào)用doLoad()方法。

第一步目前我不關(guān)心,不去深究。主要看doLoad的實(shí)現(xiàn)。

 private String doLoad(String name, ClassLoader loader) {
 String ldLibraryPath = null;
    String dexPath = null;
    if (loader == null) {
      // We use the given library path for the boot class loader. This is the path
      // also used in loadLibraryName if loader is null.
      ldLibraryPath = System.getProperty("java.library.path");
    } else if (loader instanceof BaseDexClassLoader) {
      BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader;
      ldLibraryPath = dexClassLoader.getLdLibraryPath();
    }
    // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless
    // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized
    // internal natives.
    synchronized (this) {
      return nativeLoad(name, loader, ldLibraryPath);
    }
  }

獲得libbrary的路徑;

調(diào)用native函數(shù)nativeLoad()進(jìn)行加載加載。

java_lang_Runtime.cc

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

static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader,
                 jstring javaLdLibraryPathJstr) {
 ScopedUtfChars filename(env, javaFilename);
 if (filename.c_str() == nullptr) {
  return nullptr;
 }

 SetLdLibraryPath(env, javaLdLibraryPathJstr);

 std::string error_msg;
 {
  JavaVMExt* vm = Runtime::Current()->GetJavaVM();
  bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, &error_msg);
  if (success) {
   return nullptr;
  }
 }

 // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
 env->ExceptionClear();
 return env->NewStringUTF(error_msg.c_str());
}

nativeLoad()主要做了兩件事:

第一件事:利用SetLdLibraryPath()將Java的library的path轉(zhuǎn)換成native的。

第二件事情:調(diào)用LoadNativeLibrary進(jìn)行加載。<關(guān)鍵>

java_vm_ext.cc

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

bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader,
                 std::string* error_msg) {
...
const char* 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) << "[No JNI_OnLoad found in \"" << path << "\"]";
  was_successful = true;
 } else {

利用dlopen()打開so文件,得到函數(shù)的指針

利用dlsym()調(diào)用so文件中的JNI_OnLoad方法,開始so文件的執(zhí)行。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android實(shí)現(xiàn)簡(jiǎn)單圖庫(kù)輔助器

    Android實(shí)現(xiàn)簡(jiǎn)單圖庫(kù)輔助器

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單圖庫(kù)輔助器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • android開發(fā)實(shí)現(xiàn)文件讀寫

    android開發(fā)實(shí)現(xiàn)文件讀寫

    這篇文章主要為大家詳細(xì)介紹了android開發(fā)實(shí)現(xiàn)文件讀寫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車

    Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 基于Android實(shí)現(xiàn)保存圖片到本地并可以在相冊(cè)中顯示出來

    基于Android實(shí)現(xiàn)保存圖片到本地并可以在相冊(cè)中顯示出來

    App應(yīng)用越來越人性化,不僅界面優(yōu)美而且服務(wù)也很多樣化,操作也非常方便。通過本篇文章給大家介紹基于Android實(shí)現(xiàn)保存圖片到本地并可以在相冊(cè)中顯示出來,對(duì)android保存圖片相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧
    2015-12-12
  • 在android中增加curl的解決方法

    在android中增加curl的解決方法

    本篇文章是對(duì)在android中增加curl的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Android開啟ADB網(wǎng)絡(luò)調(diào)試方法

    Android開啟ADB網(wǎng)絡(luò)調(diào)試方法

    今天小編就為大家分享一篇Android開啟ADB網(wǎng)絡(luò)調(diào)試方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • Android逆向技巧——去除開屏廣告

    Android逆向技巧——去除開屏廣告

    這篇文章主要介紹了Android如何去除開屏廣告,幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下
    2021-04-04
  • Android 高仿微信朋友圈動(dòng)態(tài)支持雙擊手勢(shì)放大并滑動(dòng)查看圖片效果

    Android 高仿微信朋友圈動(dòng)態(tài)支持雙擊手勢(shì)放大并滑動(dòng)查看圖片效果

    這篇文章主要介紹了Android 高仿微信朋友圈動(dòng)態(tài)支持雙擊手勢(shì)放大并滑動(dòng)查看圖片效果,需要的朋友參考下
    2017-01-01
  • Android中用StaticLayout實(shí)現(xiàn)文本繪制自動(dòng)換行詳解

    Android中用StaticLayout實(shí)現(xiàn)文本繪制自動(dòng)換行詳解

    StaticLayout是android中處理文字換行的一個(gè)工具類,StaticLayout已經(jīng)實(shí)現(xiàn)了文本繪制換行處理,下面這篇文章主要介紹了Android中用StaticLayout實(shí)現(xiàn)文本繪制自動(dòng)換行的相關(guān)資料,需要的朋友可以參考。
    2017-03-03
  • Android?Kotlin?中的groupBy方法詳解

    Android?Kotlin?中的groupBy方法詳解

    在Kotlin中,groupBy函數(shù)可以對(duì)集合進(jìn)行分組,形成一個(gè)Map,其中key是分組標(biāo)準(zhǔn),value是對(duì)應(yīng)的元素列表,本文通過實(shí)例詳細(xì)解釋groupBy的使用方法和常見應(yīng)用場(chǎng)景,如按員工年齡分組或產(chǎn)品類型統(tǒng)計(jì)數(shù)量等,展示了groupBy的靈活性和實(shí)用性
    2024-09-09

最新評(píng)論

新昌县| 广西| 曲靖市| 五原县| 定结县| 修文县| 罗平县| 毕节市| 蓝山县| 田东县| 光山县| 龙州县| 铅山县| 化德县| 牟定县| 中方县| 泗洪县| 深水埗区| 华安县| 土默特左旗| 故城县| 阿拉善左旗| 镇平县| 繁峙县| 巴塘县| 仪征市| 马关县| 闸北区| 长宁县| 伊金霍洛旗| 达州市| 无锡市| 平远县| 扶余县| 富蕴县| 信阳市| 德阳市| 大余县| 饶平县| 岑巩县| 水城县|