Android so文件

本篇簡單介紹Android中so文件相關事項。html

CPU架構

目前主流的CPU架構:x86,ARM,MIPSjava

它們採用的指令集又分爲CISC(複雜指令集)和RISC(精簡指令集)兩種android

CISC(複雜指令集)服務器

1.指令系統龐大,指令功能複雜,指令格式、尋址方式多網絡

2.絕大多數指令需多個機器週期完成架構

3.各類指令均可訪問存儲器app

4.採用微程序控制ide

5.有專用寄存器,少許函數

6.難以用優化編譯技術生成高效的目標代碼程序性能

RISC(精簡指令集):

1.統一指令編碼,可快速解譯;

2.泛用的暫存器,全部暫存器可用於全部內容,以及編譯器設計的單純化

3.單純的尋址模式

4.硬件中支援少數資料型別

  • x86``CISC絕大部分pc都是x86架構。

  • ARM``RISC普遍應用在嵌入式系統

  • MIPS``RISC普遍被使用在許多電子產品、網絡設備、我的娛樂裝置與商業裝置上

CPU架構和ABI

Android系統目前支持如下七種不一樣的CPU架構:ARMv5ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8MIPS64x86_64 (從2014年起),每一種都關聯着一個相應的應用程序二進制接口ABI(Application Binary Interface)。

ABI定義了二進制文件(尤爲是.so文件)如何運行在相應的系統平臺上,從使用的指令集,內存對齊到可用的系統函數庫。

ABI\CPU armeabi armeabi-v7a arm64-v8a mips
ARMv5 支持
ARMv7 支持 支持
ARMv8 支持 支持 支持
MIPS 支持
MIPS64 支持
x86 支持 支持
x86_64 支持

ABI官方介紹

so文件

  • so機制讓開發者最大化利用已有的C和C++代碼,達到重用的效果,利用軟件世界積累了幾十年的優秀代碼

  • so是二進制,沒有解釋編譯的開消,用so實現的功能比純java實現的功能要快

  • so內存分配不受Dalivik/ART的單個應用限制,減小OOM

  • 相對於java代碼,二進制代碼的反編譯難度更大,一些核心代碼能夠考慮放在so中。

so文件的加載

so文件的加載,Android在System類中提供兩種方法。

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

System.loadLibrary

這是咱們最經常使用的一個方法,System.loadLibrary只須要傳入so在Android.mk中定義的LOCAL_MODULE的值便可,系統會調用System.mapLibraryName把這個libName轉化成對應平臺的so的全稱並去嘗試尋找這個so加載。好比咱們的so文件全名爲libmath.so,加載該動態庫只須要傳入math便可:

System.loadLibrary("math");

System.load

官方介紹:

Loads a code file with the specified filename from the local file system as a dynamic library.The filename argument must be a complete path name.

因此它爲動態加載非apk打包期間內置的so文件提供了可能,也就是說可使用這個方法來指定咱們要加載的so文件的路徑來動態的加載so文件。好比咱們在打包期間並不打包so文件,而是在應用運行時將當前設備適用的so文件從服務器上下載下來,放在/data/data/ /mydir下,而後在使用so時調用:

System.load("/data/data/<package-name>/mydir/libmath.so");

便可成功加載這個so,開始調用本地方法了。

其實loadLibrary和load最終都會調用nativeLoad(name, loader, ldLibraryPath)方法,只是由於loadLibrary的參數傳入的僅僅是so的文件名,因此,loadLibrary須要首先找到這個文件的路徑,而後加載這個so文件。
而load傳入的參數是一個文件路徑,因此它不須要去尋找這個文件路徑,而是直接經過這個路徑來加載so文件。

可是當咱們把須要加載的so文件放在SdCard中,會發生什麼呢?把上面so的路徑改爲/mnt/sdcard/libmath.so,再嘗試加載時,會獲得以下錯誤:

java.lang.UnsatisfiedLinkError: dlopen failed: couldn't map "/mnt/sdcard/libmath.so" segment 1: Permission denied

這是由於SD卡等外部存儲路徑是一種可拆卸的(mounted)不可執行(noexec)的儲存媒介,不能直接用來做爲可執行文件的運行目錄,使用前應該把可執行文件複製到APP內部存儲下再運行。因此使用System.load加載so時要注意把so拷貝至/data/data/ /下。

so文件注意事項

1.不少設備都支持多於一種的ABI。但最好是針對特定平臺提供相應平臺的二進制包,從而獲得更好的性能。

2.你應該儘量的提供專爲每一個ABI優化過的.so文件,但要麼所有支持,要麼都不支持:你不該該混合着使用。你應該爲每一個ABI目錄提供對應的.so文件。
當一個應用安裝在設備上,只有該設備支持的CPU架構對應的.so文件會被安裝。在x86設備上,libs/x86目錄中若是存在.so文件的話,會被安裝,若是不存在,則會選擇armeabi-v7a中的.so文件,若是也不存在,則選擇armeabi目錄中的.so文件(由於x86設備也支持armeabi-v7a和armeabi)。

3.使用NDK時,你可能會傾向於使用最新的編譯平臺,但事實上這是錯誤的,由於NDK平臺不是後向兼容的,而是前向兼容的。推薦使用app的minSdkVersion對應的編譯平臺。

相關文章
相關標籤/搜索