亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中怎么加載so文件源碼

發布時間:2021-06-27 13:17:26 來源:億速云 閱讀:549 作者:Leah 欄目:移動開發

Android中怎么加載so文件源碼,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

要使用ndk進行編程,在Java層就必須要對so進行加載。Java層加載so的函數有兩個:

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

兩個函數的區別就是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中:

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()函數用于獲取Runtime的一個實例。

 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()函數主要進行了兩步操作。

第一步:獲取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的實現。

 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的路徑;

調用native函數nativeLoad()進行加載加載。

Android中怎么加載so文件源碼

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轉換成native的。

第二件事情:調用LoadNativeLibrary進行加載。<關鍵>

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文件,得到函數的指針

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

Android中怎么加載so文件源碼

關于Android中怎么加載so文件源碼問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

双江| 高雄县| 西城区| 东港市| 抚顺县| 乐东| 东明县| 化州市| 建宁县| 阿荣旗| 措美县| 随州市| 凤台县| 禄丰县| 克什克腾旗| 纳雍县| 凌源市| 毕节市| 灵石县| 巴南区| 富宁县| 武川县| 西乌珠穆沁旗| 万山特区| 阿拉善盟| 射阳县| 延津县| 蒲城县| 策勒县| 兴隆县| 贵南县| 石棉县| 枣庄市| 禄劝| 浦北县| 湘乡市| 财经| 鲁甸县| 五寨县| 津市市| 宣汉县|