国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

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

2019-10-22 18:14:04
字體:
來源:轉載
供稿:網友

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

要使用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文件,源碼

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 张家口市| 环江| 绵竹市| 镇远县| 石棉县| 莱芜市| 镇康县| 延川县| 包头市| 新郑市| 武鸣县| 双峰县| 瓮安县| 青阳县| 嵊泗县| 合作市| 沛县| 兴业县| 金乡县| 固安县| 青川县| 西盟| 陈巴尔虎旗| 宿州市| 丹棱县| 宜州市| 双峰县| 济宁市| 常州市| 外汇| 榆林市| 内乡县| 台东市| 彭阳县| 康马县| 永清县| 承德县| 永清县| 疏附县| 旬阳县| 南丰县|